https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions

1 基本java表达式计算

1.1 核心类

ExpressionParser parser = new SpelExpressionParser();

1.2 使用方式

字符串里面的表达式,只要符合java代码执行,则可以通过spring el进行计算,并获取结果。

String expression = "'Hello World'";
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(expression);
String message = (String) exp.getValue();
message = exp.getValue(String.class);
String expression = "'Hello World'.concat('!')";
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(expression);
String message = exp.getValue(String.class);

获取结果,进行类型转换,可以指定结果类型,也可以强制类型转换,如果类型和实际不一样,会抛出异常 EvaluationException

具体参考 Expression#getValue()

扩展:

GregorianCalendar c = new GregorianCalendar();
c.set(1856, 7, 9);

// Inventor 是一个对象
Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");

ExpressionParser parser = new SpelExpressionParser();

// 解析 name ,name是 Inventor 一个属性
Expression exp = parser.parseExpression("name");

// 在 expression 中传入 Inventor 对象,则可以调用 name 属性
String name = (String) exp.getValue(tesla);
// name == "Nikola Tesla"

exp = parser.parseExpression("name == 'Nikola Tesla'");
boolean result = exp.getValue(tesla, Boolean.class);

2 EvaluationContext

EvaluationContext 是一个接口,有2个实现,功能各有不同:

  • SimpleEvaluationContext 只有部分spring el 特性。

  • StandardEvaluationContext 更全的功能。

2.1 类型转换

class Simple {
    public List<Boolean> booleanList = new ArrayList<Boolean>();
}

Simple simple = new Simple();
simple.booleanList.add(true);

EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

// 这里设置 `booleanList[0]` 为 `false`, 传入的是一个 `false` 字符串,但是能自动转为 `boolean` 类型,并设置到 `booleanList[0]` 中。
parser.parseExpression("booleanList[0]").setValue(context, simple, "false");

// b is false
Boolean b = simple.booleanList.get(0);

3 解析配置

核心类 SpelParserConfiguration

class Demo {
    public List<String> list;
}

// 第一个参数,开启null属性,自动赋值,第二个参数,设置集合动态扩容。
SpelParserConfiguration config = new SpelParserConfiguration(true,true);

ExpressionParser parser = new SpelExpressionParser(config);

Expression expression = parser.parseExpression("list[3]");

Demo demo = new Demo();

// 表达式中是想获取 list[3] 的值,由于配置了默认初始化以及扩容,这里就会使 list 自动扩容 length 为 4,每个值为空字符串。
Object o = expression.getValue(demo);

通过配置 SpelParserConfiguration 配置2个参数。 空值初始化,以及集合自动扩展,值为指定类型的默认值。

4 编译 compiler vs 解释 interpreter

spring 框架最初提供的就是解释模式,但是性能不佳,后面提供编译模式选择,会在计算的时候生成class,提高计算性能。默认是不开启编译模式的。

4.1 编译模式有3中选项:

org.springframework.expression.spel.SpelCompilerMode 类中 - OFF (default): 默认关闭. - IMMEDIATE:尽可能快地进行表达式编译,如果失败,抛出异常 - MIXED: 混合,编译和解释2种状态转换,首选编译,如果get wrong , 则切换至解释。

4.2 示例

SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
    this.getClass().getClassLoader());

SpelExpressionParser parser = new SpelExpressionParser(config);

Expression expr = parser.parseExpression("payload");

MyMessage message = new MyMessage();

Object payload = expr.getValue(message);

4.4 complier 限制

  • 表达式中涉及任务

  • Expressions relying on the conversion service

  • Expressions using custom resolvers or accessors

  • Expressions using selection or projection

5 在定义中使用表达式

xml、以及注解方式,xml就不用了。注解使用 #{ <expression string> }.

  • 在属性上使用

  • 在set方法上使用

  • 在方法参数前使用

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

@Value("#{ systemProperties['user.region'] }")
public void setDefaultLocale(String defaultLocale) {
    this.defaultLocale = defaultLocale;
}

@Autowired
public void configure(MovieFinder movieFinder,
@Value("#{ systemProperties['user.region'] }") String defaultLocale) {
    this.movieFinder = movieFinder;
        this.defaultLocale = defaultLocale;
}

6 常见的表达式使用

6.1 字面量表达式

ExpressionParser parser = new SpelExpressionParser();

// evals to "Hello World"
String helloWorld = (String) parser.parseExpression("'Hello World'").getValue();

double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue();

// evals to 2147483647
int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue();

boolean trueValue = (Boolean) parser.parseExpression("true").getValue();

Object nullValue = parser.parseExpression("null").getValue();

6.2 属性、数组、集合表达式

// evals to 1856
int year = (Integer) parser.parseExpression("birthdate.year + 1900").getValue(context);

String city = (String) parser.parseExpression("placeOfBirth.city").getValue(context);

ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

// Inventions Array

// evaluates to "Induction motor"
String invention = parser.parseExpression("inventions[3]").getValue(
        context, tesla, String.class);

// Members List

// evaluates to "Nikola Tesla"
String name = parser.parseExpression("members[0].name").getValue(
        context, ieee, String.class);

// List and Array navigation
// evaluates to "Wireless communication"
String invention = parser.parseExpression("members[0].inventions[6]").getValue(
        context, ieee, String.class);

6.3 其他总结下,具体看官网

符号 含义

lt (<)

gt (>)

le (⇐)

ge (>=)

eq (==)

ne (!=)

div (/)

mod (%)

not (!)

and (&&)

or (||)

T(java.util.Date)

函数,java.lang 下函数只需要类名,其他的需要包名加类名

#variableName

获取变量

#this

当前

@something

bean对象

alse ? ‘trueExp’ : ‘falseExp’

If-Then-Else 三目运算符

name?:'`Unknown’

空值赋值默认值

placeOfBirth?.city

防止空指针异常

.?[selectionExpression]

集合筛选

.![projectionExpression]

集合推断

#\{ }

表达式模板

具体用法:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions-properties-arrays