跳转到内容

Spring SpEL表达式

来自代码酷

Spring表达式语言(Spring Expression Language,SpEL)是Spring框架提供的一种强大的表达式语言,支持在运行时查询和操作对象图。它类似于其他表达式语言(如OGNL或MVEL),但专为Spring生态系统设计,可与Spring配置、注解及各种Spring模块无缝集成。

概述[编辑 | 编辑源代码]

SpEL的主要特点包括:

  • 动态求值:在运行时解析表达式,支持条件逻辑和数学运算
  • 类型转换:自动处理类型转换,简化表达式编写
  • 方法调用:支持调用对象方法和构造函数
  • 集合操作:提供对集合元素的查询、筛选和投影
  • 安全访问:通过语法糖安全访问可能为null的对象

基本语法[编辑 | 编辑源代码]

SpEL表达式通常包含在#{...}分隔符中(在XML配置中),或使用T()操作符访问静态成员。表达式由字面量、属性引用、方法调用等组成。

核心功能[编辑 | 编辑源代码]

字面量表达式[编辑 | 编辑源代码]

// 数字和字符串
#{3.14159} 
#{'Hello SpEL'}

// 布尔值
#{true}

属性访问[编辑 | 编辑源代码]

支持点号记法和方括号记法:

// 假设有对象user,其name属性为"Alice"
#{user.name}  // 返回"Alice"
#{user['name']}  // 等效写法

方法调用[编辑 | 编辑源代码]

// 调用String的substring方法
#{'Spring SpEL'.substring(7)}  // 返回"SpEL"

// 调用静态方法
#{T(java.lang.Math).random()}

运算符[编辑 | 编辑源代码]

SpEL支持标准数学、关系和逻辑运算符:

SpEL运算符示例
类型 运算符 示例
+ - * / % ^ | #{2 * 3 + 5}
> >= < <= == != | #{user.age > 18}
and or not | #{not user.active}
?: | #{user.vip ? 'Premium' : 'Standard'}

集合操作[编辑 | 编辑源代码]

graph LR A[集合操作] --> B[访问元素] A --> C[筛选] A --> D[投影] A --> E[聚合]

示例:

// 访问List元素
#{users[0].name}

// 使用选择运算符(.?[])筛选
#{users.?[age > 25]}  // 返回年龄大于25的用户集合

// 使用投影运算符(.![])提取属性
#{users.![name]}  // 返回所有用户名的集合

高级特性[编辑 | 编辑源代码]

类型转换[编辑 | 编辑源代码]

SpEL自动处理基本类型转换:

// 字符串转数字
#{'100' + 5}  // 结果为105

变量上下文[编辑 | 编辑源代码]

可通过EvaluationContext设置变量:

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new EvaluationContext();
context.setVariable("limit", 100);

Expression exp = parser.parseExpression("#users.?[age > #limit]");

安全导航操作符[编辑 | 编辑源代码]

避免NullPointerException:

#{user?.address?.city}  // 如果user或address为null,返回null而非抛出异常

实际应用案例[编辑 | 编辑源代码]

案例1:动态配置[编辑 | 编辑源代码]

@Value注解中使用SpEL:

@Value("#{systemProperties['user.timezone']}")
private String timezone;

@Value("#{T(java.lang.Math).random() * 100.0}")
private double randomPercentage;

案例2:Spring Security表达式[编辑 | 编辑源代码]

在安全配置中使用SpEL:

@PreAuthorize("hasRole('ADMIN') or #user.id == authentication.name")
public void updateUser(User user) {
    // 方法实现
}

案例3:XML配置中的条件注入[编辑 | 编辑源代码]

<bean id="dataSource" class="com.example.DataSource">
    <property name="cacheSize" value="#{systemEnvironment['CACHE_SIZE'] ?: 100}"/>
</bean>

性能考虑[编辑 | 编辑源代码]

  • SpEL表达式在首次求值时会被编译,后续调用性能接近原生Java代码
  • 复杂表达式应考虑缓存Expression对象
  • 避免在频繁调用的代码路径中使用复杂SpEL表达式

最佳实践[编辑 | 编辑源代码]

1. 优先使用简单表达式,复杂逻辑应移入Java代码 2. 对重复使用的表达式进行预编译 3. 在可能为null的对象链中使用安全导航操作符 4. 为表达式添加清晰的注释说明业务意图

数学表达式支持[编辑 | 编辑源代码]

SpEL支持通过解析失败 (语法错误): {\displaystyle 标记处理数学公式: <math> E = mc^2 } 在表达式中可这样使用:

#{T(java.lang.Math).pow(mass, 2) * speedOfLight}

总结[编辑 | 编辑源代码]

Spring SpEL为Spring应用程序提供了强大的运行时表达式处理能力,从简单的属性访问到复杂的条件逻辑都能优雅处理。通过合理使用SpEL,可以显著减少样板代码,提高配置的灵活性和可读性。