SpEL(Spring Expression Language)学习笔记
一、什么是 SpEL?
SpEL(Spring Expression Language) 是 Spring 框架提供的一种强大的表达式语言,用于在运行时查询和操作对象图。
- 类似于:JSP EL、OGNL、Thymeleaf 表达式等
- 主要作用:动态注入值、调用方法、操作对象与集合、逻辑判断等
- 使用范围:
- Spring 配置(XML / 注解)
- @Value 注解
- Spring Security 表达式
- Spring Data(如 @Query)
- Thymeleaf 等模板引擎
二、基本语法
- 表达式写法:使用
#{ ... }
包含 - 示例:
<property name="name" value="#{'Hello, SpEL'}" />
@Value("#{systemProperties['user.name']}") private String userName;
三、SpEL 常见用法
1️⃣ 字面量
类型 | 示例 |
---|---|
数字 | #{123} , #{3.14} |
字符串 | #{'Hello SpEL'} |
布尔值 | #{true} , #{false} |
2️⃣ 引用 Bean、属性、方法
假设有一个 Bean:
@Component
public class User {private String name = "Alice";// getter 方法public String getName() { return name; }
}
使用方式:
@Value("#{user}") // 注入整个 User 对象
@Value("#{user.name}") // 获取属性 name 的值
@Value("#{user.getName()}") // 调用方法
@Value("#{user.getName().toUpperCase()}") // 方法链式调用
3️⃣ 运算符
① 算术运算
#{1 + 2 * 3} // 7
#{(1 + 2) * 3} // 9
#{10 % 3} // 1 (取余)
② 调用静态方法
#{T(java.lang.Math).random()} // 随机数 [0,1)
#{T(java.lang.Math).PI} // 圆周率 PI
T(全限定类名)
用于引用类,可调用其静态方法和字段。
③ 关系运算
#{age > 18}
#{score >= 60}
#{name == 'Tom'}
#{name != 'Jerry'}
④ 逻辑运算
#{age > 18 && score > 60}
#{age < 18 || hasDiscount}
⑤ 三元运算符(条件表达式)
#{score >= 60 ? '及格' : '不及格'}
4️⃣ 集合操作
假设一个 Bean 中定义了:
public class DataBean {private List<String> names = Arrays.asList("Alice", "Bob", "Cathy");private Map<String, Integer> scores = new HashMap<>();// scores.put("Alice", 90);
}
使用方式:
@Value("#{dataBean.names[0]}") // Alice(第一个元素)
@Value("#{dataBean.names[1]}") // Bob
@Value("#{dataBean.scores['Alice']}") // 90// 集合过滤
@Value("#{dataBean.names.?[startsWith('A')]}" ) // 找出以 A 开头的名字// 集合投影 / 选择
@Value("#{dataBean.names.![toUpperCase()]}") // 所有名字转大写// 首尾元素
@Value("#{dataBean.names.^[0]}") // 第一个元素
@Value("#{dataBean.names.$[2]}"} // 第三个元素(或根据实现可能是最后一个)
?[]
:过滤集合^[0]
:第一个元素$[0]
或.[size-1]
:最后一个元素(视具体版本而定).![]
:对每个元素执行操作(投影)
5️⃣ 其他特性
功能 | 说明 | 示例 |
---|---|---|
调用静态字段/方法 | 使用 T(类全名) | #{T(java.lang.Math).PI} |
正则匹配 | 使用 matches 方法 | #{user.name matches '[A-Za-z]+'} |
空安全导航 | 避免 NPE,如 ?. (SpEL 自身不直接支持,但可通过方法避免) | 建议配合方法设计 |
四、SpEL 常见使用场景
✅ 1. @Value 动态注入
@Value("#{systemProperties['user.dir']}") // 系统属性
@Value("#{T(java.lang.Math).random() * 100}") // 随机数
@Value("#{userService.currentUser.name}") // 引用其他 Bean 的属性
✅ 2. Spring XML 配置
<bean id="example" class="com.example.Example"><property name="message" value="#{'Hello, ' + 'SpEL'}" /><property name="value" value="#{T(java.lang.Math).PI}" />
</bean>
✅ 3. Spring Security 权限控制
@PreAuthorize("hasRole('ADMIN') or #id == authentication.principal.id")
public void deleteUser(Long id) {// 只有管理员或本人可以删除
}
五、SpEL 核心符号/关键字
符号/关键字 | 说明 |
---|---|
#{...} | SpEL 表达式语法 |
#root | 表达式上下文的根对象 |
#this | 当前正在处理的对象 |
#variable | 表达式内定义的变量 |
T(类全名) | 引用类,用于调用静态方法/字段 |
?[] | 集合过滤 |
^[0] | 第一个元素 |
$[0] | 最后一个元素(某些实现) |
六、SpEL 优点总结
优点 | 说明 |
---|---|
✅ 强大灵活 | 支持对象操作、方法调用、集合处理、逻辑运算等 |
✅ 动态性 | 表达式在运行时解析,支持动态值 |
✅ 与 Spring 无缝集成 | 广泛用于配置、注解、安全、数据访问等 |
✅ 可读性好 | 语法直观,易于理解和使用 |
七、📌 小结:SpEL 常用表达式速查
功能 | 示例 |
---|---|
字符串字面量 | #{'Hello SpEL'} |
数字运算 | #{1 + 2 * 3} |
调用方法 | #{user.getName()} |
调用静态方法 | #{T(Math).random()} |
属性引用 | #{user.name} |
三元表达式 | #{score >= 60 ? '及格' : '不及格'} |
集合取值 | #{dataBean.names[0]} |
集合过滤 | #{dataBean.names.?[startsWith('A')]} |
系统属性 | #{systemProperties['user.name']} |
🎯 建议学习路径
- 掌握基础语法:字面量、引用、运算符
- 学会引用 Bean 和属性:
#{bean.property}
- 尝试方法调用与静态方法:
#{bean.method()}
,#{T(Math).PI}
- 练习集合操作:过滤、取元素、遍历等
- 在实际场景使用:如 @Value 注入、XML 配置、权限控制等