Spring 系列篇之表达式语言(SpEL)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 系列篇之表达式语言(SpEL)相关的知识,希望对你有一定的参考价值。

参考技术A

Spring 表达式语言(SpEL)支持在运行时查询和操作对象。本篇文章我们来学习,如何使用SpEL,并简单介绍下,他在IoC容器中,扮演什么角色。

首先我来看一张类图,图中红框标注的是SpEL中重要的角色(接口)。

可以看到当我们需要使用SpEL时,需要有这几步操作

创建parse对象

定义表达式执行上下文

解析字符串为List

解析字符串为Map

解析执行方法,这里需要注意 #plus ,当我们需要引用变量时需要加 # 号

模板表达式,这里需要注意的是,我们需要定义模板格式,也就是需要告知解析器哪些是需要解析成表达式的,这个格式定义需要实现 ParseContext 接口, ParserContext.TEMPLATE_EXPRESSION 是Spring提供的默认格式(表达式需要用 #expression )

Spring 容器中也是支持SpEL的。因为在 AbstractApplicationContext.prepareBeanFactory 方法中会添加 BeanExpressionResolver (Bean定义的表达式解析接口)对象值, BeanExpressionResolver 本身是一个接口,定义如下,其主要作用就是根据一个表达式解析出对象。他的实现类是 StandardBeanExpressionResolver

StandardBeanExpressionResolver 内部是包装了 ExpressionParser 对象,我们在看看 evaluate 的实现,可以确定的是 StandardBeanExpressionResolver 对象解析也是使用了SpEL。

还记得 @Value 这个注解么,我们经常用他来对我们的属性赋值,如下

是直接给变量赋 name

是获取容器中b对象age属性值

是获取配置文件中name值

Spring系列.SpEL表达式

Spring表达式语言

SpEL语言是一种强大的表达式语言,支持在运行时查询和操作对象。SpEL表达式不一定要创建IOC容器后才能使用。用户完全可以单独调用SpEL的API来独立的使用时SpEL表达式。SpEL表达式支持如下的特性:

  • 文字表达式;
  • 布尔关系表达式;
  • 正则表达式;
  • 类表达式;
  • 获取数组和map;
  • 方法调用;
  • 赋值;
  • 应用IOC容器中的Bean;

SpEL简单例子

    //文字表达式(Literal expressions);
    //需要特别注意的是SpEL整个表达式需要用""括起来,里面的字符串用‘‘括起来
    ExpressionParser parser = new SpelExpressionParser();
	Expression exp = parser.parseExpression("‘Hello World‘"); 
	String message = (String) exp.getValue();
    
    //调用一个对象的方法(Method invocation)
    ExpressionParser parser = new SpelExpressionParser();
	Expression exp = parser.parseExpression("‘Hello World‘.concat(‘!‘)"); 
	String message = (String) exp.getValue();
       
    ExpressionParser parser = new SpelExpressionParser();
    //如果bytes是一个对象的public属性,则直接调用这个属性
    //否则调用对象的getBytes()这个方法
    Expression exp = parser.parseExpression("‘Hello World‘.bytes"); 
	byte[] bytes = (byte[]) exp.getValue();

    //调用构造函数
    ExpressionParser parser = new SpelExpressionParser();
	Expression exp = parser.parseExpression("new String(‘hello world‘).toUpperCase()"); 
	String message = exp.getValue(String.class);

    //获取一个对象的属性,注意getValue时,需要将对象作为入参
    // The constructor arguments are name, birthday, and nationality.
    Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian");
    ExpressionParser parser = new SpelExpressionParser();
	Expression exp = parser.parseExpression("name"); 
	String name = (String) exp.getValue(tesla);
	// name == "Nikola Tesla"
	exp = parser.parseExpression("name == ‘Nikola Tesla‘");
	boolean result = exp.getValue(tesla, Boolean.class);
	// result == true

在Bean定义中使用SpEL

    //调用类的静态方法
	<bean id="numberGuess" class="org.spring.samples.NumberGuess">
	    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>
	</bean>

    //调用其他Bean的属性,其中numberGuess是一个Bean的id,这个Bean有个randomNumber属性
    <bean id="shapeGuess" class="org.spring.samples.ShapeGuess">
	    <property name="initialShapeSeed" value="#{ numberGuess.randomNumber }"/>
    </bean>

Language Reference

Literal Expressions

将一个字符串定义为表达式

    ExpressionParser parser = new SpelExpressionParser();
	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();

Inline Data

    List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context);
    List listOfLists = (List) parser.parseExpression("{{‘a‘,‘b‘},{‘x‘,‘y‘}}").getValue(context);

	Map inventorInfo = (Map) parser.parseExpression("{name:‘Nikola‘,dob:‘10-July-1856‘}").getValue(context);
	Map mapOfMaps = (Map) parser.parseExpression("{name:{first:‘Nikola‘,last:‘Tesla‘},dob:{day:10,month:‘July‘,year:1856}}").getValue(context);

参考博客

下面给出一些常用列子

    ExpressionParser parser = new SpelExpressionParser();
    Expression exp = parser.parseExpression("‘Hello World‘.bytes");
    byte[] bytes = (byte[]) exp.getValue();

    //调用一个类的静态方法
    @Value("#{T(java.lang.Math).random()}")
    private String randomValue;

    //调用一个Bean的方法
    @Value("#{randomValueGenerator.randValue()}")
    private String randomValue1;

    //调用其他bean的属性,这个属性必须是public的
    @Value("#{randomValueGenerator.age}")
    private String value;

    //获取系统变量的值
    //也可以通过占位符的方式获取
    @Value("#{systemProperties[‘user.dir‘]}")
    private String systemValue;

    @Value("#{systemEnvironment[‘user.dir‘]}")
    private String getSystemValue1;
    
    @Value("#{‘${arrayConfig}‘.split(‘,‘)}")
    private String[] array;

    @Value("#{‘${intArray}‘.split(‘,‘)}")
    private int[] intArray;

以上是关于Spring 系列篇之表达式语言(SpEL)的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot 基础系列SpEL 语法扫盲与查询手册

Spring表达式语言:SpEL语法

Spring表达式语言:SpEL语法

Spring学习笔记--Spring表达式语言SpEL

带有@Value 的 Spring 表达式语言 (SpEL):美元与哈希($ 与 #)

Spring表达式语言 之 5.1 概述 5.2 SpEL基础(拾叁)