SpEL¶
使用 SpEL¶
// 方式一
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();
// 方式二
@Value("#{ systemProperties['user.region'] }")
private String defaultLocale;
SpEL 支持两种 EvaluationContext 用于计算表达式(解析属性、方法、字段,执行类型转换):
SimpleEvaluationContextStandardEvaluationContext
SimpleEvaluationContext 是 SpEL 语言语法的子集,不包括 Java 类型引用、构造函数和 bean 引用,
还需要显式选择表达式中属性和方法的支持级别。
可以使用解析器配置对象 ( SpelParserConfiguration ) 来配置 SpEL 表达式解析器。可以实现:
编译模式
ClassLoader
是否自动为 null 引用创建对象
是否自动增加长集合大小
集合自动增加的极限
表达式长度最大为 10,000 个字符,可以通过参数 spring.context.expression.maxLength 修改。
编译表达式¶
可以通过 spring.expression.compiler.mode 配置设置模式
public enum SpelCompilerMode {
/**
* The compiler is switched off; this is the default.
*/
OFF,
/**
* In immediate mode, expressions are compiled as soon as possible (usually after 1 interpreted run).
* If a compiled expression fails it will throw an exception to the caller.
*/
IMMEDIATE,
/**
* In mixed mode, expression evaluation silently switches between interpreted and compiled over time.
* After a number of runs the expression gets compiled. If it later fails (possibly due to inferred
* type information changing) then that will be caught internally and the system switches back to
* interpreted mode. It may subsequently compile it again later.
*/
MIXED
}
IMMEDIATE 模式之所以存在,是因为 MIXED 模式可能会导致具有副作用的表达式出现问题。如果编译表达式在部分成功后崩溃,则它可能已经做了一些影响系统状态的事情。如果发生这种情况,调用者可能不希望它以解释模式静默地重新运行,因为表达式的一部分可能会运行两次。
无法编译以下类型的表达式:
包含赋值
依赖转换服务(conversion)
使用自定义的 resolvers 或 accessors
使用集合选择器或投影( selection or projection)
SpEL语法¶
对象属性:
user.name.firstName数组、列表访问:
array[3]map 访问:
map['key1']创建内部列表:
{1,2,3,4},{{'a','b'},{'x','y'}}创建内部映射:
{name:'Nikola',dob:'10-July-1856'},{:}代表空映射方法调用:
'abc'.substring(1, 3),isMember('Mihajlo Pupin')赋值:
parser.parseExpression("name").setValue(context, inventor, "Aleksandar Seovic")parser.parseExpression("name = 'Aleksandar Seovic'").getValue(context, inventor, String.class)
变量:
newPrimes = #primes,内置变量#this和#root#primes.?[#this > 10]#root.primes需要先设置
context.setVariable("primes", primes);
函数:
#reverseString('hello')需要先注册,
context.setVariable("reverseString",StringUtils.class.getDeclaredMethod("reverseString", String.class));
引用 Bean:
@serviceImplA需要设置
context.setBeanResolver(new BeanFactoryResolver(beanFactory));
Elvis 操作符:
name?:'Unknown'等价于
name != null ? name : "Unknown"(像猫王的发型,所以叫这个名字,🤯)
安全访问符:
placeOfBirth?.city集合选择器:
members.?[nationality == 'Serbian'],map.?[value<27](key 和 value)集合投影:
"members..map(…).collect())表达式模板:
random number is #{T(java.lang.Math).random()}