【第五章】Spring表达式语言 之 5.4在Bean定义中使用EL—跟我学spring3

5.4.1 xml风格的配置

SpEL支持在Bean定义时注入,默认使用“#{SpEL表达式}”表示,其中“#root”根对象默认可以认为是ApplicationContext,只有ApplicationContext实现默认支持SpEL,获取根对象属性其实是获取容器中的Bean。

首先看下配置方式(chapter5/el1.xml)吧:


java代码:
  1. <beanid="world"class="java.lang.String">
  2. <constructor-argvalue="#{'World!'}"/>
  3. </bean>
  4. <beanid="hello1"class="java.lang.String">
  5. <constructor-argvalue="#{'Hello'}#{world}"/>
  6. </bean>
  7. <beanid="hello2"class="java.lang.String">
  8. <constructor-argvalue="#{'Hello'+world}"/>
  9. <!--不支持嵌套的-->
  10. <!--<constructor-argvalue="#{'Hello'#{world}}"/>-->
  11. </bean>
  12. <beanid="hello3"class="java.lang.String">
  13. <constructor-argvalue="#{'Hello'+@world}"/>
  14. </bean>

模板默认以前缀“#{”开头,以后缀“}”结尾,且不允许嵌套,如“#{'Hello'#{world}}”错误,如“#{'Hello' + world}”中“world”默认解析为Bean。当然可以使用“@bean”引用了。


接下来测试一下吧:


java代码:
  1. @Test
  2. publicvoidtestXmlExpression(){
  3. ApplicationContextctx=newClassPathXmlApplicationContext("chapter5/el1.xml");
  4. Stringhello1=ctx.getBean("hello1",String.class);
  5. Stringhello2=ctx.getBean("hello2",String.class);
  6. Stringhello3=ctx.getBean("hello3",String.class);
  7. Assert.assertEquals("HelloWorld!",hello1);
  8. Assert.assertEquals("HelloWorld!",hello2);
  9. Assert.assertEquals("HelloWorld!",hello3);
  10. }


是不是很简单,除了XML配置方式,Spring还提供一种注解方式@Value,接着往下看吧。

5.4.2 注解风格的配置

基于注解风格的SpEL配置也非常简单,使用@Value注解来指定SpEL表达式,该注解可以放到字段、方法及方法参数上。

测试Bean类如下,使用@Value来指定SpEL表达式:


java代码:
  1. packagecn.javass.spring.chapter5;
  2. importorg.springframework.beans.factory.annotation.Value;
  3. publicclassSpELBean{
  4. @Value("#{'Hello'+world}")
  5. privateStringvalue;
  6. //setter和getter由于篇幅省略,自己写上
  7. }


首先看下配置文件(chapter5/el2.xml):


java代码:
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="
  6. http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  8. http://www.springframework.org/schema/context
  9. http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  10. <context:annotation-config/>
  11. <beanid="world"class="java.lang.String">
  12. <constructor-argvalue="#{'World!'}"/>
  13. </bean>
  14. <beanid="helloBean1"class="cn.javass.spring.chapter5.SpELBean"/>
  15. <beanid="helloBean2"class="cn.javass.spring.chapter5.SpELBean">
  16. <propertyname="value"value="haha"/>
  17. </bean>
  18. </beans>


配置时必须使用“<context:annotation-config/>”来开启对注解的支持。


有了配置文件那开始测试吧:


java代码:
  1. @Test
  2. publicvoidtestAnnotationExpression(){
  3. ApplicationContextctx=newClassPathXmlApplicationContext("chapter5/el2.xml");
  4. SpELBeanhelloBean1=ctx.getBean("helloBean1",SpELBean.class);
  5. Assert.assertEquals("HelloWorld!",helloBean1.getValue());
  6. SpELBeanhelloBean2=ctx.getBean("helloBean2",SpELBean.class);
  7. Assert.assertEquals("haha",helloBean2.getValue());
  8. }


其中“helloBean1 ”值是SpEL表达式的值,而“helloBean2”是通过setter注入的值,这说明setter注入将覆盖@Value的值。


5.4.3 在Bean定义中SpEL的问题

如果有同学问“#{我不是SpEL表达式}”不是SpEL表达式,而是公司内部的模板,想换个前缀和后缀该如何实现呢?

那我们来看下Spring如何在IoC容器内使用BeanExpressionResolver接口实现来求值SpEL表达式,那如果我们通过某种方式获取该接口实现,然后把前缀后缀修改了不就可以了。

此处我们使用BeanFactoryPostProcessor接口提供postProcessBeanFactory回调方法,它是在IoC容器创建好但还未进行任何Bean初始化时被ApplicationContext实现调用,因此在这个阶段把SpEL前缀及后缀修改掉是安全的,具体代码如下:


java代码:
  1. packagecn.javass.spring.chapter5;
  2. importorg.springframework.beans.BeansException;
  3. importorg.springframework.beans.factory.config.BeanFactoryPostProcessor;
  4. importorg.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  5. importorg.springframework.context.expression.StandardBeanExpressionResolver;
  6. publicclassSpELBeanFactoryPostProcessorimplementsBeanFactoryPostProcessor{
  7. @Override
  8. publicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory)
  9. throwsBeansException{
  10. StandardBeanExpressionResolverresolver=(StandardBeanExpressionResolver)beanFactory.getBeanExpressionResolver();
  11. resolver.setExpressionPrefix("%{");
  12. resolver.setExpressionSuffix("}");
  13. }
  14. }


首先通过 ConfigurableListableBeanFactory的getBeanExpressionResolver方法获取BeanExpressionResolver实现,其次强制类型转换为StandardBeanExpressionResolver,其为Spring默认实现,然后改掉前缀及后缀。


开始测试吧,首先准备配置文件(chapter5/el3.xml):


java代码:
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="
  6. http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  8. http://www.springframework.org/schema/context
  9. http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  10. <context:annotation-config/>
  11. <beanclass="cn.javass.spring.chapter5.SpELBeanFactoryPostProcessor"/>
  12. <beanid="world"class="java.lang.String">
  13. <constructor-argvalue="%{'World!'}"/>
  14. </bean>
  15. <beanid="helloBean1"class="cn.javass.spring.chapter5.SpELBean"/>
  16. <beanid="helloBean2"class="cn.javass.spring.chapter5.SpELBean">
  17. <propertyname="value"value="%{'Hello'+world}"/>
  18. </bean>
  19. </beans>


配置文件和注解风格的几乎一样,只有SpEL表达式前缀变为“%{”了,并且注册了“cn.javass.spring.chapter5.SpELBeanFactoryPostProcessor”Bean,用于修改前缀和后缀的。

写测试代码测试一下吧:


java代码:
  1. @Test
  2. publicvoidtestPrefixExpression(){
  3. ApplicationContextctx=newClassPathXmlApplicationContext("chapter5/el3.xml");
  4. SpELBeanhelloBean1=ctx.getBean("helloBean1",SpELBean.class);
  5. Assert.assertEquals("#{'Hello'+world}",helloBean1.getValue());
  6. SpELBeanhelloBean2=ctx.getBean("helloBean2",SpELBean.class);
  7. Assert.assertEquals("HelloWorld!",helloBean2.getValue());
  8. }



此处helloBean1 中通过@Value注入的“#{'Hello' + world}”结果还是“#{'Hello' + world}”说明不对其进行SpEL表达式求值了,而helloBean2使用“%{'Hello' + world}”注入,得到正确的“"Hello World!”。


你可能感兴趣的:(Spring3)