SpEL 表达式语言基础

引言

在配置和注解里常看到 #{...} 的写法:@Value("#{...}")@EventListener(condition = "...") 甚至缓存 key 模板。这是 Spring 表达式语言(SpEL)——在运行时对字符串表达式求值的统一能力。本章掌握 SpEL 的语法骨架与求值入口,够用即可,不必背全量语法。

核心概念

  • 三件套(org.springframework.expression)ExpressionParser(解析器,标准实现 SpelExpressionParser)、Expression(解析结果,可反复求值)、EvaluationContext(求值上下文,提供根对象与变量)。
  • 字面量与运算:字符串/数字/布尔、算术比较逻辑运算、三元、?:(Elvis 缺省)、?.(安全导航,null 不炸)。
  • 属性与方法访问user.namelist[0]map['key']name.toUpperCase()
  • 类型引用 T()T(java.lang.Math).random() 调静态方法/常量。
  • 根对象与变量:求值上下文里的 #root#thissetVariable("x", v) 后用 #x 引用。
  • Security 要点(官方推荐):处理不可信输入时用 SimpleEvaluationContext(只开放基本能力),别用功能全开的 StandardEvaluationContext,后者允许通过 T() 触碰任意类,有安全风险。
  • 常用落点:@Value("#{...}")(也可 ${...} 混合)、@EventListener(condition)@Cacheable(key) 等(以各模块官方文档为准)。

代码示例

import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;

public class SpelDemo {
    public static void main(String[] args) {
        SpelExpressionParser parser = new SpelExpressionParser();

        // 基本求值:属性链 + 方法 + Elvis 缺省
        Expression exp = parser.parseExpression("name?.toUpperCase() ?: 'unknown'");
        SimpleEvaluationContext ctx = SimpleEvaluationContext
                .forReadOnlyDataBinding().build();
        ctx.setVariable("name", "spring");          // #name 变量
        System.out.println(exp.getValue(ctx, String.class)); // SPRING

        // T() 类型引用(SimpleEvaluationContext 下被限制,示例仅示意标准上下文场景)
        Expression pi = new SpelExpressionParser()
                .parseExpression("T(java.lang.Math).PI");
        System.out.println(pi.getValue());          // 3.14159...
    }
}

// 注解中的用法示例:
// @Value("#{systemProperties['user.name']}") String userName;
// @EventListener(condition = "#event.success")  // 事件满足条件才触发

注意点

  • ${...} 是属性占位符(读配置),#{...} 是 SpEL(求表达式),别混:@Value("${a.b}") vs @Value("#{...}")
  • SpEL 在 @Value 里求值发生在 Bean 初始化期,表达式抛错会让 Bean 创建失败。
  • 对用户输入开放 SpEL = 潜在的表达式注入,官方明确建议不可信输入走 SimpleEvaluationContext 或干脆禁用(以官方文档为准)。
  • 表达式解析一次、可复用 Expression 对象多次求值,别在热路径里反复 parse。
  • 集合投影/选择(![]/.?[])等高级语法按需查官方参考,不必一次记全。

小结

SpEL = 解析器 + 表达式 + 求值上下文。语法上记住“属性链、运算、Elvis/安全导航、T() 类型、#变量”就够覆盖日常;安全上牢记 SimpleEvaluationContext 与 StandardEvaluationContext 的分界线。它是 Spring 各模块“可配置逻辑”的公共底座。

笔记加载中…