Spring中表達式語言spring-expression簡單使用


前言

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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM