前言
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)