1. 程式人生 > >【第五章】Spring表示式語言 之 5.4在Bean定義中使用EL—跟我學spring3

【第五章】Spring表示式語言 之 5.4在Bean定義中使用EL—跟我學spring3

5.4.1  xml風格的配置

       SpEL支援在Bean定義時注入,預設使用“#{SpEL表示式}”表示,其中“#root”根物件預設可以認為是ApplicationContext,只有ApplicationContext實現預設支援SpEL,獲取根物件屬性其實是獲取容器中的Bean。

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

java程式碼:
  1. <bean id="world"class="java.lang.String">  
  2.     <constructor-arg value="#{' World!'}"/>  
  3. </bean>  
  4. <bean id="hello1"class="java.lang.String">  
  5.     <constructor-arg value="#{'Hello'}#{world}"/>  
  6. </bean>    
  7. <bean id="hello2"class="java.lang.String">  
  8.     <constructor-arg value="#{'Hello' + world}"/>  
  9.     <!-- 不支援巢狀的 -->  
  10.     <!--<constructor-arg value="#{'Hello'#{world}}"
    />-->  
  11. </bean>  
  12. <bean id="hello3"class="java.lang.String">  
  13.     <constructor-arg value="#{'Hello' + @world}"/>  
  14. </bean>  

       模板預設以字首“#{”開頭,以後綴“}”結尾,且不允許巢狀,如“#{'Hello'#{world}}”錯誤,如“#{'Hello' + world}”中“world”預設解析為Bean。當然可以使用“@bean”引用了。

       接下來測試一下吧:

java程式碼:
  1. @Test
  2. publicvoid testXmlExpression() {  
  3.     ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter5/el1.xml");  
  4.     String hello1 = ctx.getBean("hello1", String.class);  
  5.     String hello2 = ctx.getBean("hello2", String.class);  
  6.     String hello3 = ctx.getBean("hello3", String.class);  
  7.     Assert.assertEquals("Hello World!", hello1);  
  8.     Assert.assertEquals("Hello World!", hello2);  
  9.     Assert.assertEquals("Hello World!", hello3);  
  10. }     

       是不是很簡單,除了XML配置方式,Spring還提供一種註解方式@Value,接著往下看吧。

5.4.2  註解風格的配置

       基於註解風格的SpEL配置也非常簡單,使用@Value註解來指定SpEL表示式,該註解可以放到欄位、方法及方法引數上。

       測試Bean類如下,使用@Value來指定SpEL表示式:

java程式碼:
  1. package cn.javass.spring.chapter5;  
  2. import org.springframework.beans.factory.annotation.Value;  
  3. publicclass SpELBean {  
  4.     @Value("#{'Hello' + world}")  
  5.     private String value;  
  6.     //setter和getter由於篇幅省略,自己寫上
  7. }  

       首先看下配置檔案(chapter5/el2.xml):

java程式碼:
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans  xmlns="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.    <bean id="world"class="java.lang.String">  
  12.        <constructor-arg value="#{' World!'}"/>  
  13.    </bean>  
  14.    <bean id="helloBean1"class="cn.javass.spring.chapter5.SpELBean"/>  
  15.    <bean id="helloBean2"class="cn.javass.spring.chapter5.SpELBean">  
  16.        <property name="value" value="haha"/>  
  17.    </bean>  
  18. </beans>  

       配置時必須使用“<context:annotation-config/>”來開啟對註解的支援。

       有了配置檔案那開始測試吧:

java程式碼:
  1. @Test
  2. publicvoid testAnnotationExpression() {  
  3.     ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter5/el2.xml");  
  4.     SpELBean helloBean1 = ctx.getBean("helloBean1", SpELBean.class);  
  5.     Assert.assertEquals("Hello World!", helloBean1.getValue());  
  6.     SpELBean helloBean2 = 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. package cn.javass.spring.chapter5;  
  2. import org.springframework.beans.BeansException;  
  3. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;  
  4. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;  
  5. import org.springframework.context.expression.StandardBeanExpressionResolver;  
  6. publicclass SpELBeanFactoryPostProcessor implements BeanFactoryPostProcessor {  
  7.     @Override
  8.     publicvoid postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)  
  9.         throws BeansException {  
  10.         StandardBeanExpressionResolver resolver = (StandardBeanExpressionResolver) beanFactory.getBeanExpressionResolver();  
  11.         resolver.setExpressionPrefix("%{");  
  12.         resolver.setExpressionSuffix("}");  
  13.     }  
  14. }  

    首先通過 ConfigurableListableBeanFactory的getBeanExpressionResolver方法獲取BeanExpressionResolver實現,其次強制型別轉換為StandardBeanExpressionResolver,其為Spring預設實現,然後改掉字首及字尾。

       開始測試吧,首先準備配置檔案(chapter5/el3.xml):

java程式碼:
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans  xmlns="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.    <bean class="cn.javass.spring.chapter5.SpELBeanFactoryPostProcessor"/>  
  12.    <bean id="world"class="java.lang.String">  
  13.        <constructor-arg value="%{' World!'}"/>  
  14.    </bean>  
  15.    <bean id="helloBean1"class="cn.javass.spring.chapter5.SpELBean"/>  
  16.    <bean id="helloBean2"class="cn.javass.spring.chapter5.SpELBean">  
  17.        <property name="value" value="%{'Hello' + world}"/>  
  18.    </bean>  
  19. </beans>  

       配置檔案和註解風格的幾乎一樣,只有SpEL表示式字首變為“%{”了,並且註冊了“cn.javass.spring.chapter5.SpELBeanFactoryPostProcessor”Bean,用於修改字首和字尾的。

       寫測試程式碼測試一下吧:

java程式碼:
  1. @Test
  2. publicvoid testPrefixExpression() {  
  3.     ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter5/el3.xml");  
  4.     SpELBean helloBean1 = ctx.getBean("helloBean1", SpELBean.class);  
  5.     Assert.assertEquals("#{'Hello' + world}", helloBean1.getValue());  
  6.     SpELBean helloBean2 = ctx.getBean("helloBean2", SpELBean.class);  
  7.     Assert.assertEquals("Hello World!", helloBean2.getValue());  
  8. }      

       此處helloBean1 中通過@Value注入的“#{'Hello' + world}”結果還是“#{'Hello' + world}”說明不對其進行SpEL表示式求值了,而helloBean2使用“%{'Hello' + world}”注入,得到正確的“"Hello World!”。