spring之SpEL表达式详解
作者:sunpy 孙培煜
1.什么是SpEL表达式
SpEL表达式语言是一种表达式语言,是一种可以与一个基于spring的应用程序中的运行时对象交互的东西。有点类似于ognl表达式。总得来说SpEL表达式是一种简化开发的表达式,通过使用表达式来简化开发,减少一些逻辑、配置的编写。
2.SpEL表达式语言入门程序
(1)xml配置的方式
配置环境:pom.xml
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.0.5.RELEASE</version> </dependency> </dependencies>
applicationContext.xml文件:
<bean id="MyMessage" class="cn.spy.spel.injection.MyMessage"> <property name="message" value="#{systemProperties['user.language']}"></property> </bean>
MyMessage.java文件:
public class MyMessage { private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
测试程序:
public class Test { public static void main(String[] args) { ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml"); MyMessage myMessage =context.getBean(MyMessage.class); System.out.println(myMessage.getMessage()); } }
结果:
解释:这里使用了表达式#{systemProperties['user.language']}来设置值,用来检索用户语言系统的属性。
(2)采用注解的方式
applicationContext.xml文件:
<context:component-scan base-package="cn.spy.spel"></context:component-scan>
MyMessage2.java文件:
@Component public class MyMessage2 { @Value("#{systemProperties['user.language']}") private String message; public String getMessage() { return message; } }
解释:这里使用了@Value注解的方式,当实例化MyMessage2这个bean的时候,将使用该注解设置默认值。此处还是使用了之前的SpEL表达式,来设置用户语言系统的属性。(在这里@Value注解既可以在类的字段属性上面,也可以在构造函数和方法上面使用)。
测试:
public static void main(String[] args) { ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml"); MyMessage2 myMessage =context.getBean(MyMessage2.class); System.out.println(myMessage.getMessage()); }
结果:
3.分析器
SpEL上下文中所定义的每一个表达式都应该首先被解析,然后在被评估。解析的过程采用了ExpressionParser接口的分析器进行处理的。SpelExpressionParser主要负责将字符串表达式解析到已编译的Expression对象中。(创建的分析器实例是线程安全)
代码形式:
ExpressionParser parser =new SpelExpressionParser();
注意:
在SpEL表达式中,默认情况下,表达式前缀为 ' # ' ,而后缀为 ' } ' 。如果表达式中没有前缀和后缀,那么表达式字符串就被当作纯文本。
分析器解析Spel中纯文本表达式HelloWorld:
public class HelloWorldTest { ExpressionParser parser; @Before public void setup(){ //初始化创建SpEL表达式解析器 parser =new SpelExpressionParser(); } @Test public void test(){ //使用解析器解析出表达式exp Expression exp=parser.parseExpression("'Hello World'"); //在表达式中获取指定类型的值 String value =exp.getValue(String.class); assertThat(value ,is("Hello World")); } }
junit测试结果:
4.使用SpEL表达式调用方法
(1)使用SpEL调用普通方法
就是SpEL也支持在表达式中采用方法调用的形式
范例:
User.java:
public class User { private String username; private String password; public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public String getUsername() { return "李四"; } public String getPassword() { return "lisi123"; } public void printUser(){ System.out.println("当前用户的用户名:"+username+" ,密码:"+password); } }
applicationContext.xml配置文件:
<bean id="user1" class="cn.spy.spel.method.User"> <property name="username" value="张三"></property> <property name="password" value="zhangsan123"></property> </bean> <bean id="user2" class="cn.spy.spel.method.User"> <property name="username" value="#{user2.getUsername()}"></property> <property name="password" value="#{user2.getPassword()}"></property> </bean>
测试:
public class TestMethod { public static void main(String[] args) { ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml"); User user1 =(User) context.getBean("user1"); user1.printUser(); User user2 =(User) context.getBean("user2"); user2.printUser(); } }
结果:
(2)使用SpEL调用构造方法
@Test public void test(){ ExpressionParser parser =new SpelExpressionParser(); Expression exp=parser.parseExpression("new Double(3.1415926)"); Double value =exp.getValue(Double.class); assertThat(value ,is(3.1415926)); }
结果:
(3)使用SpEL调用静态方法
@Test public void test(){ ExpressionParser parser =new SpelExpressionParser(); Expression exp=parser.parseExpression("T(java.lang.Math).abs(-1)"); Integer value =exp.getValue(Integer.class); assertThat(value ,is(1)); }
结果:
6.使用SpEL表达式调用变量和函数
(1)#变量的表达式使用
SpEL使用上下文StandardEvaluationContext查找表达式中存在的变量。在表达式中使用变量名称前添加一个标签前缀#,使用已注册的变量。
public class TestSpEL { @Test public void test(){ ExpressionParser parser =new SpelExpressionParser(); StandardEvaluationContext context =new StandardEvaluationContext(); context.setVariable("message", "Hello World"); String value =parser.parseExpression("#message").getValue(context, String.class); assertThat(value, is("Hello World")); } }
结果:
(2)#root表达式的使用
可以在上下文中设置一个对象评估,可以使用#root访问该对象。
public class TestSpEL { @Test public void test(){ ExpressionParser parser =new SpelExpressionParser(); StandardEvaluationContext context =new StandardEvaluationContext(); context.setRootObject(new Var()); Assert.assertTrue(parser.parseExpression("#root").getValue(context) instanceof Var); } }
结果:
(3)访问系统的属性和环境
SpEL预定义变量:systemProperties和systemEnvironment
parser.parseExpression("@systemProperties['java.version']").getValue(context); parser.parseExpression("@systemProperties[JAVA_HOME]").getValue(context);
7.使用SpEL表达式中的运算符
SpEL提供了多种运算符。
类型 | 运算符 |
关系 | <,>,<=,>=,==,!=,lt,gt,le,ge,eq,ne |
算术 | +,- ,* ,/,%,^ |
逻辑 | &&,||,!,and,or,not,between,instanceof |
条件 | ?: (ternary),?: (elvis) |
正则表达式 | matches |
其他类型 | ?.,?[…],![…],^[…],$[…] |
注意:如果解析表达式时,在完全限定的类名中包含一个运算符的文本表示形式,则会产生异常。
正则表达式运算符matches
@Test public void test(){ ExpressionParser parser =new SpelExpressionParser(); assertThat(parser.parseExpression("35 matches '[0-9]+'").getValue(Boolean.class), is(true)); }
结果:
逻辑运算符between
@Test public void test(){ ExpressionParser parser =new SpelExpressionParser(); assertThat(parser.parseExpression("3 between {2,5}").getValue(Boolean.class), is(true)); }
结果:
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。