在Spring3以后,引入了强大的表达式语言-Spring Expression Language,即SpEL语言。SpEL能够在运行时构建复杂的表达式,存取对象属性,对象方法及正则表达式匹配等功能,并且其都支持XML和注解两种实现方式,其语法格式为#{SpEL Expression},并需要spring-expression这个jar包。
l 实例引用
l 方法调用
l 正则匹配
l 集合操作
我们可以在<property>元素的value属性中使用#{}界定符将值装配到Bean的属性中。
<property name="count" value="#{5}" />
浮点型数字一样可以出现在SpEL表达式中。
<property name="frequency" value="#{89.7}" />
表达式中的数字也可以实用科学计数法。
<property name="capacity" value="#{1e4}" />
这里将capacity属性设为了10000.0。
String类型的字面值可以使用单引号或者双引号作为字符串界定符。
<property name="name" value="#{'moonlit'}" />
或者
<property name="name" value='#{"moonlit"}' />
还可以使用布尔值true和false。
<property name="enabled" value="#{true}" />
引用Bean
新建Poem类。
package com.moonlit.myspring; public class Poem { private static String[] LINES = { "床前明月光,", "疑是地上霜。", "举头望明月,", "低头思故乡。", }; public void perform() { for (String line : LINES) System.out.println(line); } }
新建Poet类。
package com.moonlit.myspring; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Poet { private Poem poem; public void recite() { System.out.println("the poet begin to recite..."); poem.perform(); } public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "spring-idol.xml"); Poet poet = (Poet) context.getBean("poet"); poet.recite(); } public Poem getPoem() { return poem; } public void setPoem(Poem poem) { this.poem = poem; } }
并在xml文件中声明他们对应的Bean。
<bean id="poem" class="com.moonlit.myspring.Poem" /> <bean id="poet" class="com.moonlit.myspring.Poet"> <property name="poem" value="#{poem}"> </bean>
poet通过SpEL获得了poem这个Bean。
此时运行Poet程序得到结果如下:
the poet begin to recite... 床前明月光, 疑是地上霜。 举头望明月, 低头思故乡。
还可以通过SpEL获得bean的对象。
<property name="poem" value="#{poet.poem}" />
通过这句话就获得了poet的poem。
还可以通过SpEL获得bean的对象。
<property name="poem" value="#{poet.getPoem()}" />
通过这句话通过poet.getPoem()获得poet的poem。
在SpEL中避免抛出空指针异常(NullPointException)的方法是使用null-safe存取器:
<property name="song" value="#{songSelector.selectSong()?.toUpperCase()}" />
这里我们使用 ?. 运算符代替点(.)来访问toUpperCase()方法。在访问邮编方法之前,该运算符会确保左边项的值不为null。所以,如果selectorSong返回null,SpEL就不再尝试调用toUpperCase()方法。
操作类
在SpEL中,使用T()运算符会调用类作用域的方法和常量。例如,在SpEL中使用Java的Math类,我们可以像下面的示例这样使用T()运算符:
T(java.lang.Math)
T()运算符的结果会返回一个java.lang.Math类对象。
装配PI或者一个随机值的配置方法如下:
<property name="multiplier" value="#{T(java.lang.Math).PI}" /> <property name="randomNumber" value="#{T(java.lang.Math).random()}" />
SpEL上还可以执行bean值和数值之间的多种运算。
这里我定义一个Circle类:
package com.moonlit.myspring; public class Circle { private double radius; public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } }
它的Bean声明如下:
<bean id="circle" class="com.moonlit.myspring.Circle"> <property name="radius" value="2.1" /> </bean>
使用如下语句进行SpEL的数值运算示例:
<property name="total" value="#{circle.radius + 100.0}" />
“+”还可以进行字符串的连接。
比较值
<property name="hasCapacity" value="#{circle.radius lt 3.3}" />
操作一个表达式的值:
eq(==),lt(<),le(<=),gt(>),ge(>=)。
逻辑表达式:
and,or,not或!。
条件运算符:使用三元运算符
<property name="instrument" value="#{sonSelector.selecSOng()=='Jingle Bells'?piano:saxophone}" />
一个常见的三元运算符的使用场景是检查一个值是否为null。
<property name="song" value="#{kenny.song != null ? kenny.song : 'Greensleeves'}" />
虽然以上配置可以正常工作,但这里kenny.song的引用重复了两次。SpEL提供了三元运算符的变体来简化表达式:
<property name="song" value="#{kenny.song ?: 'Greensleeves'}" />
在以上示例中,如果kenny.song不为null,那么表达式的求值结果是kenny.song,否则就是"Greensleeves"。当我们以这种方式使用时,“?:”通常被称为elvis运算符。这个名字的来历是,使用这个运算符来表示微笑表情(?:) ,头左转90度看)时,问号看起来像猫王(Elvis Presley)的头发。
SpEL支持正则表达式匹配
<property name="validEmail" value="#{admin.email matches '[a-zA-Z0-9._%+_]+@[a-zA-Z0-9.-]+\\.com'}" />
Hero类用于演示上述的大部分效果:
package com.moonlit.myspring; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Hero { private int count; private double frequency; private double capacity; private String name; private boolean enabled; private Poem poem; private double multiplier; private double randomNumber; private double total; private boolean hasCapacity; public void perform() { System.out.println("count = " + count); System.out.println("frequency = " + frequency); System.out.println("capacity = " + capacity); System.out.println("name = " + name); System.out.println("enabled = " + enabled); System.out.println("hero begin to recite..."); poem.perform(); System.out.println("pi = " + multiplier); System.out.println("random number = " + randomNumber); System.out.println("total = " + total); System.out.println("hasCapacity = " + hasCapacity); } public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext( "spring-idol.xml"); Hero hero = (Hero) context.getBean("hero"); hero.perform(); } public int getCount() { return count; } public void setCount(int count) { this.count = count; } public double getFrequency() { return frequency; } public void setFrequency(double frequency) { this.frequency = frequency; } public double getCapacity() { return capacity; } public void setCapacity(double capacity) { this.capacity = capacity; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public Poem getPoem() { return poem; } public void setPoem(Poem poem) { this.poem = poem; } public double getMultiplier() { return multiplier; } public void setMultiplier(double multiplier) { this.multiplier = multiplier; } public double getRandomNumber() { return randomNumber; } public void setRandomNumber(double randomNumber) { this.randomNumber = randomNumber; } public double getTotal() { return total; } public void setTotal(double total) { this.total = total; } public boolean isHasCapacity() { return hasCapacity; } public void setHasCapacity(boolean hasCapacity) { this.hasCapacity = hasCapacity; } }
spring-idol.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-init-method="defaultBorn" default-destroy-method="defaultDead" > <bean id="poem" class="com.moonlit.myspring.Poem" /> <bean id="poet" class="com.moonlit.myspring.Poet"> <property name="poem" value="#{poem}" /> </bean> <bean id="circle" class="com.moonlit.myspring.Circle"> <property name="radius" value="2.1" /> </bean> <bean id="hero" class="com.moonlit.myspring.Hero"> <property name="count" value="#{5}" /> <property name="frequency" value="#{89.7}" /> <property name="capacity" value="#{1e4}" /> <!-- <property name="name" value="#{'moonlit'}" /> --> <property name="name" value='#{"moonlit"}' /> <property name="enabled" value="#{true}" /> <!-- <property name="poem" value="#{poet.poem}" /> --> <property name="poem" value="#{poet.getPoem()}" /> <property name="multiplier" value="#{T(java.lang.Math).PI}" /> <property name="randomNumber" value="#{T(java.lang.Math).random()}" /> <property name="total" value="#{circle.radius + 100.0}" /> <property name="hasCapacity" value="#{circle.radius lt 3.3}" /> </bean> </beans>
实际上,SpEL接触起来比较简单,但也很实用,其可以方便灵巧的处理各个Bean之间的操作,以及强大正则的支持等,使它的使用变得很流行!