Spring中表达式语言spring-expression简单使用

前言

Spring Expression Language(简称 SpEL)是一个支持查询和操作运行时对象导航图功能的强大的表达式语言,
它的语法类似于传统 EL(如jsp中的EL表达式),但提供额外的功能,最出色的就是函数调用和简单字符串的模板函数。

Spring中表达式语言spring-expression简单使用

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)

上一篇:LINQ to SQL与IQueryable


下一篇:行为型模式 - 解释器模式