SpEL 能写什么、在哪里被求值?表达式里出错会是什么样?用户输入的表达式为什么危险?每次解析和复用解析结果差多少?这篇在 Spring Framework 7.0.9 上逐项验证。
upper=ALICE | adult=成年 | second=b | math+10=100 | lang=en | T(Math).max=7 | user?.friend?.name=null | ${missing:#{user.name}}=alice可以引用 Bean、调用方法与静态方法,用 ?. 避免空指针,也能和 ${} 占位符组合。
name → alice
name.length() → 5
age * 2 + 1 → 61
tags.size() > 2 → true
tags[0] + tags[2] → ac
score['math'] → 90
hello('bob') → hello bob from alice
friend?.name → null
friend.name → ✗ SpelEvaluationException: EL1007E: Property or field 'name' cannot be found on null
new String('x').toUpperCase() → X
T(java.lang.System).currentTimeMillis() > 0 → true
tags.![toUpperCase()] → [A, B, C]
tags.?[#this != 'b'] → [a, c]
'abc' matches '[a-c]+' → true
#root.age → 30
secret → ✗ SpelEvaluationException: EL1008E: Property or field 'secret' cannot be found on object of type 'demo.Main$User' - maybe not p…
nope → ✗ SpelEvaluationException: EL1008E: Property or field 'nope' cannot be found on object of type 'demo.Main$User' - maybe not pub…集合投影与过滤、matches、三元;在 null 上取属性、取不到的字段都有明确的错误码。
StandardEvaluationContext 下 T(java.lang.Runtime).getRuntime().availableProcessors() → 10(能调任意类的静态方法) SimpleEvaluationContext.forReadOnlyDataBinding() 下同一个表达式 → ✗ SpelEvaluationException: EL1005E: Type cannot be found 'java.lang.Runtime' SimpleEvaluationContext 读 name → alice 只读上下文里赋值 name = 'x' → ✗ SpelEvaluationException: EL1068E: The expression component 'name='x'' is not assignable
Standard 上下文能访问任意类型,Simple 上下文把类型和写入都限制住。
每次 parseExpression 加求值:1315 ns/次;解析一次后反复求值:96 ns/次;编译模式(IMMEDIATE):6.5 ns/次;直接写 Java:1.99 ns/次(s=61000000 防止被优化掉) 每次 parseExpression 加求值:1227 ns/次;解析一次后反复求值:96 ns/次;编译模式(IMMEDIATE):5.0 ns/次;直接写 Java:2.01 ns/次(s=61000000 防止被优化掉) 每次 parseExpression 加求值:1219 ns/次;解析一次后反复求值:96 ns/次;编译模式(IMMEDIATE):6.6 ns/次;直接写 Java:1.73 ns/次(s=61000000 防止被优化掉)
解析是大头,解析一次复用能省一个数量级,编译模式再省一个数量级。