关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言
前一段时间看到JetCache
框架的源码中使用了Spring SpEL
,回想到之前看到某框架的源码时,也看到类似的技术。于是自己也试着学习一下。
我们一直在借助框架使用着SpEL
技术,但是可能却不能单独拎出来使用过。Spring
中有很多实用的工具类,我们可以直接使用。
今天我们一起看看SpEL
的表达式的用法。
02 基本概念
Spring
表达式语言(SpEL
)是一种强大的表达式解析框架,集成于 Spring
生态中,用于在运行时动态计算表达式值。SpelExpressionParser
是 SpEL
的核心解析器,能够将字符串表达式转换为可执行的 Expression
对象,支持对象属性访问、方法调用、运算符操作、集合处理等复杂逻辑。
典型应用场景:
- Spring 注解(如
@Value
) - Spring Security 权限表达式
- XML/注解配置的动态参数
- 规则引擎、动态公式计算
- 模板渲染(如 Thymeleaf)
03 案例
3.1 基础使用案例
解析简单的表达式。
java
@Test
void test01() {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'.concat('!')");
String message = (String) exp.getValue();
System.out.println(message);
// Hello World!
Expression intExp = parser.parseExpression("25 * 4");
Integer message = (Integer) intExp.getValue();
System.out.println(message);
// 100
Expression boolExp = parser.parseExpression("100 > 50 && true");
System.out.println(boolExp.getValue());
// 输出: true
}
简单来说,就是将一个字符串解析成对应的运算或者方法调用。
3.2 对象属性访问与方法调用
通过上下文访问对象或者调用对象的方法
java
@Test
void test02() {
User user = new User("Alice", 30);
ExpressionParser parser = new SpelExpressionParser();
// 创建上下文并绑定对象
EvaluationContext context = new StandardEvaluationContext(user);
// 访问属性
Expression nameExp = parser.parseExpression("name");
// 从上下文中获取对象属性
System.out.println(nameExp.getValue(context));
// 输出: Alice
// 调用方法
Expression methodExp = parser.parseExpression("setName('Bob')");
methodExp.getValue(context); // 执行setName方法
System.out.println(user.getName());
// 输出: Bob
// 链式操作
Expression chainExp = parser.parseExpression("name.toUpperCase().length()");
System.out.println(chainExp.getValue(context));
// 输出: 3 (BOB的长度)
}
绑定上下文有两种方式:
- 构造函数:
new StandardEvaluationContext(user)
Setter
方法:new StandardEvaluationContext().setVariable("user", user);
两种方式的取值各不相同:
- 构造函数取值:直接获取属性
parser.parseExpression("name");
Setter
方法取值:通过#
号调用parser.parseExpression("#user.name");
3.3 集合的操作
SpEL
支持对集合进行过滤、投影等操作:
java
@Test
void test03() {
List<User> users = Arrays.asList(
new User("Alice", 25),
new User("Bob", 30),
new User("Charlie", 20)
);
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("users", users);
ExpressionParser parser = new SpelExpressionParser();
// 过滤年龄>25的用户
Expression filterExp = parser.parseExpression("#users.?[age > 25]");
List<User> filtered = (List<User>) filterExp.getValue(context);
filtered.forEach(u -> System.out.println(u.getName()));
// 输出: Bob
// 提取所有用户名
Expression mapExp = parser.parseExpression("#users.![name.toUpperCase()]");
List<String> names = (List<String>) mapExp.getValue(context);
System.out.println(names);
// 输出: [ALICE, BOB, CHARLIE]
}
值得说明的是:提取集合的某个属性时,用到的!
,过滤或者取值用到?
04 使用注意事项
4.1 安全风险
从3.2
案例中,可以看到:我们是可以随意修改上下文变量的值的。如果担心被人恶意篡改上下文参数,我们需要使用org.springframework.expression.spel.support.SimpleEvaluationContext
的限制功能(默认禁用类型构造、方法调用):
java
SimpleEvaluationContext simpleContext = SimpleEvaluationContext.forReadOnlyDataBinding().build();
exp.getValue(simpleContext); // 安全模式
再次修改参数就是出现下面的报错:

4.2 空值的处理
NPE
是每一个程序员都会遇到的异常,我们看看Spring SpEL
如何处理:使用 ?.
安全导航操作符避免 NPE
java
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("book", null);
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("#book?.bookName");
// 返回 null,不会出现NPE
4.3 类型转化
明确指定返回值类型:
java
String name = exp.getValue(context, String.class);
05 小结
SpelExpressionParser
是 Spring 生态中处理动态表达式的利器,通过简洁的语法实现了:
- 对象属性/方法动态访问
- 复杂集合操作
- 与 Spring 配置深度集成
掌握 SpEL 能显著提升开发灵活性,尤其在需要动态配置的场景中(如规则引擎、个性化配置),但务必警惕安全风险,做好防护措施。