本章內容
- spring prifile
- 條件話的bean聲明
- 自動裝配與歧義性
- bean的作用域
- Spring表達式語言
3.1 環境與profile
軟件開發的生命週期中,很多時候涉及到環境的遷移,而各種環境的配置文件會有所不同.最簡單的方式就是爲不同的階段配置不同的配置類或者xml文件.然後在構建的時候確定使用哪一個.
- 配置 profile bean
①: spring會在運行的時候確定使用哪個配置文件,這樣的好處是同一個部署(可能會是war)單元能夠適應所有的環境,沒有必要進行重新構建.
在java配置中使用@Profile 註解指定某個bean屬於哪個profile 在3.1版本中@Profile是類級別的註解,從3.2開始是方法級別的註解與@Bean註解一同使用,這樣就可以將bean的聲明放到同一個配置類之中. —特別注意bean聲明在profile中,並且只有當規定的profile激活時,相應的bean纔會被創建.
②:在xml中配置profile
我們可以使用 < beans > 元素的profile屬性,在xml中配置 profile bean.
<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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd" profile="qa"> <!-- 可以配置多個配置文件 在這裏做區分 不同的文件命名 profile="qa"-->
</beans>
也可以在同一個xml中引入不同的beans標籤
<?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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--測試環境的配置文件-->
<beans profile="qa">
<context:property-placeholder location="classpath:environment.properties"/>
</beans>
<!--生產環境的配置文件-->
<beans profile="pro">
<context:property-placeholder location="file:${ENVIRONMENT_FILE}"/>
</beans>
</beans>
3.1.2激活profile
Spring 在確定那個profile激活狀態時,需要依賴2個獨立的屬性
spring.profiles.active 和spring.profoles.default.如果設置了spring.profiles.active屬性的話,那麼它的值就會用來確定哪個profile是激活的.但是如果沒有設置的話spring會查找spring.profiles.default的值.如果都沒有設置的話,那就沒有激活的profile,因此只會創建那些沒有定義在profile中的bean
可以用多種方式來設置這2個屬性
- 作爲DispatcherServlet的初始化參數;
- 作爲Web應用上下文的參數;
- 作爲JNDI條目
- 作爲環境變量
- 作爲JVM的系統屬性
- 在集成測試類上,使用@ActiveProfiles註解設置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- 爲上下文設置默認的profile -->
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>qa</param-value>
</context-param>
<!-- 爲Servlet設置默認的profile -->
<servlet>
<init-param>
<param-name>spring.profiles.default</param-name>
<param-value>qa</param-value>
</init-param>
</servlet>
</web-app>
當設置spring.profiles.active以後,系統會優先使用active中所設置的profile.就會不關心default的設置了
profile使用的是複數的形式,這意味着可以同時激活多個profile.多個之間使用,分隔來實現
<beans profile="qa,dev,pro">
<context:property-placeholder location="file:${ENVIRONMENTS_FILE}"/>
</beans>
- 使用profile進行測試
如果配置中的bean定義在了profile中,那麼運行測試的時候,我們需要有一種方式來啓用合適的profile
spring提供了註解@ActiveProfiles激活profile
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring.xml")
@ActiveProfiles("dev")
public class AlsTest {
@Test
public void testApp()throws Exception{
}
}
3.2 條件話的bean
在條件話初始bean方面spring的profile機制是一種很棒的方法,這裏的條件要基於那個profile處於激活狀態來判斷.spring4.0提供了一種更爲通用的機制來實現條件話的bean定義,在這種機制下,條件完全由自己確定.
假設你希望一個或者多個bean在滿足指定的條件下才會創建.spring4.0引入了一個新的註解@Conditional註解,它可以用到帶有@bean的註解上.如果給定的條件結果爲true就會創建這個bean.否則的話被忽略
//可以看到@Condition中給定了一個Class,它指明瞭條件,在本例中MagicExistsCondition會通過Condition接口進行條件對比
@Bean
@Conditional(MagicExistsCondition.class)
public MagicBean magicBean(){
return new MagicBean();
}
/**
* 設置給Conditional的類可以是任意實現了Condition接口的類型
* 這個接口只需要實現matches()方法即可
*/
public class MagicExistsCondition implements Condition {
/**
*通過給定的ConditionContext對象進而得到Environment對象,並使用這個對象檢查環境中是否存在名爲magic的環境屬性,
* 屬性值是什麼無所謂,只要屬性存在即可滿足要求,bean就會被創建,屬性不存在不滿足bean就不會被創建
* 如果這個屬性不存在的話,就無法滿屋條件,返回false,就不會被創建
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment env = context.getEnvironment();
return env.containsProperty("magic");//檢查magic屬性
}
}
MagicExistsCondition 中只是用了CoditionContext得到的Environment,但是Condition實現的考量因爲會更多.matches()方法會得到ConditionContext和AnnotateTypeMetadata對象來做出決策
通過ConditionContext ,我們可以做到如下幾點
- 藉助getRegistry()返回