Spring表达式语言:SpEL

1)Spring表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言。

2)语法类似于EL:SpEL使用#{...}作为界定符,所有在大框号中的字符都被认为是SpEL。

3)SpEL为bean属性进行动态赋值提供了便利。

4)通过SpEL可以实现:

---通过bean的id对bean进行引用

---调用方法以及引用对象中的属性

---计算表达式的值

---正则表达式的匹配

实现原理:ExpressionParser解析器

SpEL上下文中所定义的每一个表达式都应该首先被解析,然后在被评估。解析的过程采用了ExpressionParser接口的分析器进行处理的。SpelExpressionParser主要负责将字符串表达式解析到已编译的Expression对象中。(创建的分析器实例是线程安全)

使用示例:

ExpressionParser parser = new SpelExpressionParser(); 

注意:

在SpEL表达式中,默认情况下,表达式前缀为 ' # ' ,而后缀为 ' } ' 。如果表达式中没有前缀和后缀,那么表达式字符串就被当作纯文本。

@Test
public void test(){
ExpressionParser parser =new SpelExpressionParser();
assertThat(parser.parseExpression("3 between {2,5}").getValue(Boolean.class), is(true));
}

1)maps的内容由内指定的key值获得. 在这种情况下,因为对于人员的键映射是字符串,我们可以指定 字符串

// Officer's Dictionary
Inventor pupin = parser.parseExpression("Officers['president']").getValue(societyContext, Inventor.class); // evaluates to "Idvor"
String city = parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(societyContext, String.class); // setting values
parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext, "Croatia");

2)内联列表列表可以直接在表达式中使用{}符号来表示。

// evaluates to a Java list containing the four numbers
List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context); List listOfLists = (List) parser.parseExpression("{{'a','b'},{'x','y'}}").getValue(context);

{}本身意味着空列表。出于性能的考虑,如果列表本身 完全由固定面值的则恒定列表被创建以代表 表达,而不是建立一个新的列表上的每个都执行。

3)内联maps{key:value}记号的maps也可以使用表达式直接表示。

// evaluates to a Java map containing the two entries
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);

更多参考《https://blog.csdn.net/z69183787/article/details/51882741》

SpEL:字面量

字面量的表示:

- 整数:

<property name="count" value="#{5}" />

- 小数:

<property name="price" value="#{35.5}" />

- 科学计数法:

<property name="capacity" value="#{1e3}" />

- String 可以使用单引号或者双引号作为字符串的定界符号:

<property name="categoryName" value="#{'article'}" />
或者
<property name="categoryName" value="#{“article“}" />

- Boolean:

<property name="isComplete" value="#{false}" />

SpEL:引用bean、属性和方法

1)引用其他对象:

<bean id="car" class="com.dx.beans.Car" />
<bean id="person" class="com.dx.beans.Person">
<property name="car" value="#{car}"></property>
</bean>

2)引用其他对象的属性

<bean id="address" class="com.dx.beans.Address" />
<bean id="person" class="com.dx.beans.Person">
<property name="car" value="#{car}"></property>
<property name="city" value="#{address.city}"></property>
</bean>

3)调用其他方法,还可以链式操作

<bean id="car" class="com.dx.beans.Car" />
<bean id="person" class="com.dx.beans.Person">
<property name="carInfo" value="#{car.toString().toUpperCase()}"></property>
</bean>

SpEL支持的运算符号

1)算数运算符:+ - * / % ^

<property name="theValue" value="#{cou.price + 42}"/>
<property name="theValue" value="#{cou.price - 42}"/>
<property name="theValue" value="#{2 * T(java.lang.Math).PI * circle.radius}"/>
<property name="theValue" value="#{cou.price/cou.count}"/>
<property name="theValue" value="#{cou.price%cou.count}"/>
<property name="theValue" value="#{T(java.lang.Math).PI * circle.radius ^ 2}"/>

2)加号还可以用作字符串连接:

<property id="fullname" value="#{person.firstname + ' ' + person.lastname}"/>

3)比较运算符:> < == <= >= lt gt eq le ge

<property id="equal100"  value="#{produce.price==100}"/>
<property id="hasCapacity" value="#{produce.price le 10000}"/>

4)逻辑运算符号:and or not  !

<property name="largeCircle" value="#{shape.kind=='circle' and shape.perimeter gt 10000}"/>
<property name="outOfStock" value="#{!product.available}"/>
<property name="outOfStock" value="#{not product.available}"/>

5)条件运算 if-else 运算符: ?:(termary) 或者 ?:(Elvis)

如果我们希望在某个条件为true 时,SpEL 表达式的求值结果是某个值;如果该条件为false 时,它的求值结果是另一个值,那么这要如何实现呢?使用?:符号。

(1)如果student Bean的sex属性为true,则把boy装配给sex属性,否则装配girl。

<property name="sex" value="#{student.sex == true ? 'boy' : 'girl'}"/>

(2)如果kenny.song 不为null,那么表达式的求值结果是kenny.song,否则就是“Greensleeves”。当我们以这种方式使用时,“?:”通常被称为elvis 运算符

<property name="song" value="#{kenny.song ?: 'Greensleeves'}"/> 

6)正则表达式

matches 运算符对String 类型的文本(作为左边参数)应用正则表达式(作为右边参数)。matches 的运算结果将返回一个布尔类型的值:如果与正则表达式相匹配,则返回true ;否则返回false。
假设我们想判断一个字符串是否是有效的邮件地址。
<property name="validEmail" value= "#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.com'}"/> 

SpEL:引用Bean、属性和方法

调用静态方法或者静态属性:通过T()调用一个类的静态方法,它返回一个Class Object,然后再调用相应的方法或属性。

<proerpty name="initValue" value="#{T(java.lang.Math).PI}"/>

Spring(十一):Spring配置Bean(四)SpEL的更多相关文章

  1. Spring入门第一课:Spring基础与配置Bean

    1.入门 Spring是简化java开发的一个框架,其中IoC和AOP是Spring的两个重要核心.由于Spring是非侵入性的,通过Ioc容器来管理bean的生命周期,还整合了许多其他的优秀框架,所 ...

  2. Spring下如何配置bean

    本次讲述项目背景: 创建Service类,Service下用到dao类.通过在Spring中配置bean,实现在项目启动时,自动加载这个类 本次只讲述配置bean的注意事项,故只给出简单实例: 创建S ...

  3. 5. Spring 通过 XML 配置 bean (进阶)

    1. 设置 bean 的作用域 当通过 Spring IOC 容器创建 bean 实例的时候,不仅可以完成 bean 的实例化,也可以为 bean 指定特定的作用域,Spring 支持以下 5 种作用 ...

  4. Spring 通过工厂配置Bean

    1.通过静态工厂方法配置Bean 要声明通过静态方法创建的 Bean, 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类, 同时在 factory-method 属性里指定工厂方法的名 ...

  5. 12.Spring通过FactoryBean配置Bean

    为啥要使用FactoryBean: 在配置Bean的时候,需要用到IOC容器中的其它Bean,这个时候使用FactoryBean配置最合适. public class Car { private St ...

  6. Spring通过注解配置Bean

    @Component: 基本注解, 标识了一个受 Spring 管理的组件@Repository: 标识持久层组件@Service: 标识服务层(业务层)组件@Controller: 标识表现层组件 ...

  7. Spring IOC实现配置bean和实例

    配置 beans.xml文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=&quo ...

  8. spring 注解方式配置Bean

    Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件特定组件包括: @Component:基本注解,标示了一个受Spring管理的Bean组件 @Respository:标识 ...

  9. Spring 通过FactoryBean配置Bean

    1.实现FactoryBean接口 import org.springframework.beans.factory.FactoryBean; public class CarFactoryBean ...

  10. Spring官网阅读(四)BeanDefinition(上)

    前面几篇文章已经学习了官网中的1.2,1.3,1.4三小结,主要是容器,Bean的实例化及Bean之间的依赖关系等.这篇文章,我们继续官网的学习,主要是BeanDefinition的相关知识,这是Sp ...

随机推荐

  1. [Go] sync.Pool 的实现原理 和 适用场景

    摘录一: Go 1.3 的 sync 包中加入一个新特性:Pool. 官方文档可以看这里 http://golang.org/pkg/sync/#Pool 这个类设计的目的是用来保存和复用临时对象,以 ...

  2. 自定义两行可左右滑动的GridView

    效果图: xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:an ...

  3. WinForm通用自动更新器AutoUpdater项目实战

    一.项目背景介绍 最近单位开发一个项目,其中需要用到自动升级功能.因为自动升级是一个比较常用的功能,可能会在很多程序中用到,于是,我就想写一个自动升级的组件,在应用程序中,只需要引用这个自动升级组件, ...

  4. CefSharp 在同一窗口打开链接的方法

    摘要 在winform中使用cefsharp的时候,我们在浏览网页的时候,想在同一个窗口打开链接,而不是创建新的窗口.可以通过下面的方法实现. 解决方案 CefSharp 中控制弹窗的接口是 ILif ...

  5. .Net Discovery系列之十一-深入理解平台机制与性能影响 (中)

    上一篇文章中Aicken为大家介绍了.Net平台的垃圾回收机制与其对性能的影响,这一篇中将继续为大家介绍.Net平台的另一批黑马—JIT.   有关JIT的机制分析   ● 机制分析   以C#为例, ...

  6. python脚本从excel表到处数据,生成指定格式的文件

    #coding:gbk #导入处理excel的模块 import xlrd #定义哪些字段须要推断,仅仅支持时间字段 toSureColArray = ['CREATE_TIME','MODIFY_T ...

  7. 发布网站时应该把debug设置false

    在ASP.NET项目根目录下的Web.config中有这样的一个节点: <compilation debug="true" targetFramework="4.5 ...

  8. The Win32 Rundll and Rundll32 Interface Related Topics

    The Win32 Rundll and Rundll32 Interface Related Topics Microsoft Knowledge Base Article Q164787 Appl ...

  9. I/O会一直占用CPU吗?【转载】

    转自:https://www.zhihu.com/question/27734728 知乎上看到的一个提问,可以参考 如下图:(图片摘自网络) 在进行I/O操作的时候,是将任务交给DMA来处理,请求发 ...

  10. C#编程(七十三)----------浅析C#中内存管理

    浅析C#中内存管理 前言:个人觉得C#吸收了各种语言的优点,可谓集大成者,但是不知但,这种集所有语言于一身的情况是好是坏.C#编程的一个优点就是程序员不需要关心具体的内存管理,尤其是垃圾收集器会处理所 ...