前言
Spring Expression Language(简称 SpEL)是一个支持查询和操作运行时对象导航图功能的强大的表达式语言,
它的语法类似于传统 EL(如jsp中的EL表达式),但提供额外的功能,最出色的就是函数调用和简单字符串的模板函数。
SpEL 作为Spring框架的基础,但并不依赖于Spring容器,可以独立使用。
简单使用
引入maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
简单字面量
支持字符串,日期,数值(整型,浮点型,十六进制),布尔等类型
//创建表达式解析器
ExpressionParser expressionParser = new SpelExpressionParser();
//解析表达式并获取结果
System.out.println(expressionParser.parseExpression("'hello'").getValue());
System.out.println(expressionParser.parseExpression("123").getValue());
System.out.println(expressionParser.parseExpression("12.34").getValue());
System.out.println(expressionParser.parseExpression("10e2").getValue());
System.out.println(expressionParser.parseExpression("true").getValue());
System.out.println(expressionParser.parseExpression("new java.util.Date()").getValue());
输出结果为
hello
123
12.34
1000.0
true
Sat Sep 25 19:39:38 CST 2021
变量引用
通过#'变量名'的方式来使用变量
//创建表达式解析器
ExpressionParser expressionParser = new SpelExpressionParser();
//创建数据上下文
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
//设置变量
evaluationContext.setVariable("a", 12);
evaluationContext.setVariable("b", 34);
evaluationContext.setVariable("c", 56);
//解析表达式
System.out.println(expressionParser.parseExpression("#a+#b-#c").getValue(evaluationContext));
输出为
-10
对象的属性和方法
定义一个普通bean
public class User {
private String name;
public User(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
通过对象.属性的方式来引用
//创建表达式解析器
ExpressionParser expressionParser = new SpelExpressionParser();
//创建数据上下文
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setVariable("user", new User("lisi"));
System.out.println(expressionParser.parseExpression("#user.name").getValue(evaluationContext));
System.out.println(expressionParser.parseExpression("#user.getName()").getValue(evaluationContext));
输出为
lisi
lisi
数组,集合,map
//创建表达式解析器
ExpressionParser expressionParser = new SpelExpressionParser();
//创建数据上下文
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
//设置数组变量
evaluationContext.setVariable("users", new User[]{new User("Tom")});
//设置集合变量
evaluationContext.setVariable("userList", Collections.singletonList(new User("Mary")));
//设置map变量
evaluationContext.setVariable("userMap", Collections.singletonMap("u123", new User("u123")));
System.out.println(expressionParser.parseExpression("#users[0].name").getValue(evaluationContext));
System.out.println(expressionParser.parseExpression("#userList[0].name").getValue(evaluationContext));
System.out.println(expressionParser.parseExpression("#userMap['u123'].name").getValue(evaluationContext));
输出为
Tom
Mary
u123
普通方法调用
和在Java中使用没有区别
//创建表达式解析器
ExpressionParser expressionParser = new SpelExpressionParser();
System.out.println(expressionParser.parseExpression("'hello'.substring(2)").getValue());
输出为
llo
操作符
支持关系操作符(大于 小于 等于),逻辑操作符(and or not),算数操作符(加减乘除)
//创建表达式解析器
ExpressionParser expressionParser = new SpelExpressionParser();
System.out.println(expressionParser.parseExpression("1 < 4").getValue());
System.out.println(expressionParser.parseExpression("1 < 4 and 5 > 9 ").getValue());
System.out.println(expressionParser.parseExpression("1 + 3 - 5").getValue());
引用IOC容器中的bean
定义bean的配置文件
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean
public User user() {
return new User("lisi");
}
}
默认支持#{}的格式来引用bean
//创建表达式解析器
ExpressionParser expressionParser = new SpelExpressionParser();
//创建数据上下文
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
//创建IOC容器上下文
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
//创建bean表达式上下文
BeanExpressionContext beanExpressionContext = new BeanExpressionContext((ConfigurableBeanFactory) context.getAutowireCapableBeanFactory(), null);
evaluationContext.setRootObject(beanExpressionContext);
//添加属性访问器 从IOC容器中获取bean
evaluationContext.addPropertyAccessor(new BeanExpressionContextAccessor());
System.out.println(expressionParser.parseExpression("#{user.name}", new TemplateParserContext()).getValue(evaluationContext));
输出为
lisi
@Value注解
我们在项目中很多地方都会用到@Value注解
@Value("${name}")
private String name;
@Value("#{person.name}")
private String personName;
解析@Value注解的过程就会使用到SpEL
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
//字符串类型就表示是@Value注解注入
if (value instanceof String) {
// 使用StringValueResolver处理${}占位符
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
//处理bean表达式,#{}这种格式
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
...
...
}
@Nullable
protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
if (this.beanExpressionResolver == null) {
return value;
}
Scope scope = null;
if (beanDefinition != null) {
String scopeName = beanDefinition.getScope();
if (scopeName != null) {
scope = getRegisteredScope(scopeName);
}
}
return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}
}
默认使用的beanExpressionResolver为StandardBeanExpressionResolver。
参考
Spring学习总结(四)——表达式语言 Spring Expression Language
【小家Spring】SpEL你感兴趣的实现原理浅析spring-expression~(SpelExpressionParser、EvaluationContext、rootObject)