【第五章】Spring表示式語言 之 5.4在Bean定義中使用EL—跟我學spring3
5.4.1 xml風格的配置
SpEL支援在Bean定義時注入,預設使用“#{SpEL表示式}”表示,其中“#root”根物件預設可以認為是ApplicationContext,只有ApplicationContext實現預設支援SpEL,獲取根物件屬性其實是獲取容器中的Bean。
首先看下配置方式(chapter5/el1.xml)吧:
java程式碼:- <bean id="world"class="java.lang.String">
-
<constructor-arg value="#{' World!'}"/>
- </bean>
- <bean id="hello1"class="java.lang.String">
- <constructor-arg value="#{'Hello'}#{world}"/>
- </bean>
- <bean id="hello2"class="java.lang.String">
- <constructor-arg value="#{'Hello' + world}"/>
- <!-- 不支援巢狀的 -->
-
<!--<constructor-arg value="#{'Hello'#{world}}"
- </bean>
- <bean id="hello3"class="java.lang.String">
- <constructor-arg value="#{'Hello' + @world}"/>
- </bean>
模板預設以字首“#{”開頭,以後綴“}”結尾,且不允許巢狀,如“#{'Hello'#{world}}”錯誤,如“#{'Hello' + world}”中“world”預設解析為Bean。當然可以使用“@bean”引用了。
接下來測試一下吧:
java程式碼:- @Test
- publicvoid testXmlExpression() {
- ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter5/el1.xml");
- String hello1 = ctx.getBean("hello1", String.class);
- String hello2 = ctx.getBean("hello2", String.class);
- String hello3 = ctx.getBean("hello3", String.class);
- Assert.assertEquals("Hello World!", hello1);
- Assert.assertEquals("Hello World!", hello2);
- Assert.assertEquals("Hello World!", hello3);
- }
是不是很簡單,除了XML配置方式,Spring還提供一種註解方式@Value,接著往下看吧。
5.4.2 註解風格的配置
基於註解風格的SpEL配置也非常簡單,使用@Value註解來指定SpEL表示式,該註解可以放到欄位、方法及方法引數上。
測試Bean類如下,使用@Value來指定SpEL表示式:
java程式碼:- package cn.javass.spring.chapter5;
- import org.springframework.beans.factory.annotation.Value;
- publicclass SpELBean {
- @Value("#{'Hello' + world}")
- private String value;
- //setter和getter由於篇幅省略,自己寫上
- }
首先看下配置檔案(chapter5/el2.xml):
java程式碼:- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:annotation-config/>
- <bean id="world"class="java.lang.String">
- <constructor-arg value="#{' World!'}"/>
- </bean>
- <bean id="helloBean1"class="cn.javass.spring.chapter5.SpELBean"/>
- <bean id="helloBean2"class="cn.javass.spring.chapter5.SpELBean">
- <property name="value" value="haha"/>
- </bean>
- </beans>
配置時必須使用“<context:annotation-config/>”來開啟對註解的支援。
有了配置檔案那開始測試吧:
java程式碼:- @Test
- publicvoid testAnnotationExpression() {
- ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter5/el2.xml");
- SpELBean helloBean1 = ctx.getBean("helloBean1", SpELBean.class);
- Assert.assertEquals("Hello World!", helloBean1.getValue());
- SpELBean helloBean2 = ctx.getBean("helloBean2", SpELBean.class);
- Assert.assertEquals("haha", helloBean2.getValue());
- }
其中“helloBean1 ”值是SpEL表示式的值,而“helloBean2”是通過setter注入的值,這說明setter注入將覆蓋@Value的值。
5.4.3 在Bean定義中SpEL的問題
如果有同學問“#{我不是SpEL表示式}”不是SpEL表示式,而是公司內部的模板,想換個字首和字尾該如何實現呢?
那我們來看下Spring如何在IoC容器內使用BeanExpressionResolver介面實現來求值SpEL表示式,那如果我們通過某種方式獲取該介面實現,然後把字首字尾修改了不就可以了。
此處我們使用BeanFactoryPostProcessor介面提供postProcessBeanFactory回撥方法,它是在IoC容器建立好但還未進行任何Bean初始化時被ApplicationContext實現呼叫,因此在這個階段把SpEL字首及字尾修改掉是安全的,具體程式碼如下:
java程式碼:- package cn.javass.spring.chapter5;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
- import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
- import org.springframework.context.expression.StandardBeanExpressionResolver;
- publicclass SpELBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
- @Override
- publicvoid postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
- throws BeansException {
- StandardBeanExpressionResolver resolver = (StandardBeanExpressionResolver) beanFactory.getBeanExpressionResolver();
- resolver.setExpressionPrefix("%{");
- resolver.setExpressionSuffix("}");
- }
- }
首先通過 ConfigurableListableBeanFactory的getBeanExpressionResolver方法獲取BeanExpressionResolver實現,其次強制型別轉換為StandardBeanExpressionResolver,其為Spring預設實現,然後改掉字首及字尾。
開始測試吧,首先準備配置檔案(chapter5/el3.xml):
java程式碼:- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:annotation-config/>
- <bean class="cn.javass.spring.chapter5.SpELBeanFactoryPostProcessor"/>
- <bean id="world"class="java.lang.String">
- <constructor-arg value="%{' World!'}"/>
- </bean>
- <bean id="helloBean1"class="cn.javass.spring.chapter5.SpELBean"/>
- <bean id="helloBean2"class="cn.javass.spring.chapter5.SpELBean">
- <property name="value" value="%{'Hello' + world}"/>
- </bean>
- </beans>
配置檔案和註解風格的幾乎一樣,只有SpEL表示式字首變為“%{”了,並且註冊了“cn.javass.spring.chapter5.SpELBeanFactoryPostProcessor”Bean,用於修改字首和字尾的。
寫測試程式碼測試一下吧:
java程式碼:- @Test
- publicvoid testPrefixExpression() {
- ApplicationContext ctx = new ClassPathXmlApplicationContext("chapter5/el3.xml");
- SpELBean helloBean1 = ctx.getBean("helloBean1", SpELBean.class);
- Assert.assertEquals("#{'Hello' + world}", helloBean1.getValue());
- SpELBean helloBean2 = ctx.getBean("helloBean2", SpELBean.class);
- Assert.assertEquals("Hello World!", helloBean2.getValue());
- }
此處helloBean1 中通過@Value注入的“#{'Hello' + world}”結果還是“#{'Hello' + world}”說明不對其進行SpEL表示式求值了,而helloBean2使用“%{'Hello' + world}”注入,得到正確的“"Hello World!”。