内联列表 (Inline Lists)
可以使用 {} 标记法在表达式中直接表示列表。
java
// 评估结果为一个包含四个数字的 Java List
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
// 嵌套列表
List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);kotlin
// 评估结果为一个包含四个数字的 Java List
val numbers = parser.parseExpression("{1,2,3,4}").getValue(context) as List<*>
// 嵌套列表
val listOfLists = parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context) as List<*>单独的 {} 表示一个空列表。出于性能原因,如果列表本身完全由固定字面量组成,则会创建一个常量列表来表示该表达式(而不是在每次评估时都构建一个新列表)。
补充教学
1. 为什么不用 new ArrayList()?
在 SpEL 中,{1,2,3} 是一种更加声明式的语法,就像 Python 的 [1,2,3]。它不仅代码更短,而且语义更清晰。它生成的底层对象通常是不可变列表(或者为了性能进行了特殊优化的列表)。
2. 常见应用场景:权限与过滤
你最常在 Spring Security 的注解中见到这种语法:
- 角色检查:
@PreAuthorize("hasAnyRole({'ROLE_ADMIN', 'ROLE_USER'})") - 默认值补全:在
@Value中初始化一个列表:java@Value("#{{'standard', 'premium', 'vip'}}") private List<String> accountTypes;
3. 注意事项:与 JSON 的区别
虽然 {} 看起来像 JSON 的对象,但在 SpEL 中:
{}是列表 (List)。{key:value}才是映射 (Map)(详见下一章“内联 Map”)。 不要因为习惯了 JSON 语法而在这里产生混淆。
4. 性能优化:重复执行的开销
正如官方文档提到的,如果你写的是字面量列表(如 {'A', 'B'}),Spring 会在解析阶段就将其“冻结”为一个常量。这意味着如果你在一个高频调用的方法(如循环处理 10 万行数据)中使用这个表达式,它不会创建 10 万个 List 对象,这极大地减轻了垃圾回收 (GC) 的压力。