在java配置中,能夠使用@ProFile註解制定某個Bean屬於哪個profile。例如:@Profile("dev")。java
在xml中配置profile 經過<beans>元素的profile屬性,在XML中配置profile bean 。linux
<!-- 開發環境配置文件 --> <beans profile="test"> <context:property-placeholder location="/WEB-INF/test-orm.properties" /> </beans> <!-- 本地環境配置文件 --> <beans profile="local"> <context:property-placeholder location="/WEB-INF/local-orm.properties" /> </beans>
profile的定義必定要在文檔的最下邊,不然會有異常。整個xml的結構大概是這樣git
<beans xmlns="..." ...> <bean id="dataSource" ... /> <bean ... /> <beans profile="..."> <bean ...> </beans> </beans>
Spring在肯定那個Profile處於激活狀態時,依賴兩個獨立的屬性:spring.profiles.active 和spring.profiles.default。若是設置了spring.profiles.active屬性的話,那麼他的值就會用來肯定那個profile是激活的,可是若是沒有設置 spring.profiles.active屬性的話,就會查找 spring.profiles.default的值,若是spring.profiles.active 和 spring.profiles.default 均沒有設置的話,那就沒有激活的profile,只會建立那些沒有定義在profile中的bean。 設置激活屬性的方式:web
好比咱們在web.xml中能夠聲明代碼以下spring
<?xml version="1.0" encoding="UTF-8"?> <web -app version="2.5" ...> //爲上下文設置默認的profile <context-param> <param-name>spring.profile.default</param-name> <param-value>dev</param-value> </context-param> ... <servlet> ... //爲Serlvet設置默認的profile <init-param> <param-name>spring-profiles.default</param-name> <param-value>dev</param-value> </init-prama> ... <web-app>
另外對於測試,spring爲何提供了一個簡單的註解能夠使用@ActiveProfiles,它能夠指定運行測試的時候應該要激活那個profile。好比這裏的測試類DevDataSourceTestsql
package profiles; import static org.junit.Assert.*; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import javax.sql.DataSource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.myapp.DataSourceConfig; public class DataSourceConfigTest { @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=DataSourceConfig.class) @ActiveProfiles("dev") public static class DevDataSourceTest { @Autowired private DataSource dataSource; @Test public void shouldBeEmbeddedDatasource() { assertNotNull(dataSource); JdbcTemplate jdbc = new JdbcTemplate(dataSource); List<String> results = jdbc.query("select id, name from Things", new RowMapper<String>() { @Override public String mapRow(ResultSet rs, int rowNum) throws SQLException { return rs.getLong("id") + ":" + rs.getString("name"); } }); assertEquals(1, results.size()); assertEquals("1:A", results.get(0)); } } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=DataSourceConfig.class) @ActiveProfiles("prod") public static class ProductionDataSourceTest { @Autowired private DataSource dataSource; @Test public void shouldBeEmbeddedDatasource() { // should be null, because there isn't a datasource configured in JNDI assertNull(dataSource); } } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:datasource-config.xml") @ActiveProfiles("dev") public static class DevDataSourceTest_XMLConfig { @Autowired private DataSource dataSource; @Test public void shouldBeEmbeddedDatasource() { assertNotNull(dataSource); JdbcTemplate jdbc = new JdbcTemplate(dataSource); List<String> results = jdbc.query("select id, name from Things", new RowMapper<String>() { @Override public String mapRow(ResultSet rs, int rowNum) throws SQLException { return rs.getLong("id") + ":" + rs.getString("name"); } }); assertEquals(1, results.size()); assertEquals("1:A", results.get(0)); } } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:datasource-config.xml") @ActiveProfiles("prod") public static class ProductionDataSourceTest_XMLConfig { @Autowired(required=false) private DataSource dataSource; @Test public void shouldBeEmbeddedDatasource() { // should be null, because there isn't a datasource configured in JNDI assertNull(dataSource); } } }
一、ENV方式:windows
ConfigurableEnvironment.setActiveProfiles("test")
二、JVM參數方式: tomcat 中 catalina.bat(.sh中不用「set」) 添加JAVA_OPS。經過設置active選擇不一樣配置文件數組
set JAVA_OPTS="-Dspring.profiles.active=test"
eclipse 中啓動tomcat。項目右鍵 run as –> run configuration–>Arguments–> VM arguments中添加。local配置文件沒必要上傳git追蹤管理tomcat
-Dspring.profiles.active="local"
三、web.xml方式:session
<init-param> <param-name>spring.profiles.active</param-name> <param-value>production</param-value> </init-param>
四、標註方式(junit單元測試很是實用):
@ActiveProfiles({"unittest","productprofile"})
spring4 引入一個新的@Conditional 註解它能夠用到@Bean註解的方法上,若是給定的條件計算結果爲true,就差建立這個bean,不然的話,這個bean就會被忽略。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class MyConfiguration { @Bean(name="emailerService") @Conditional(WindowsCondition.class) public EmailService windowsEmailerService(){ return new WindowsEmailService(); } @Bean(name="emailerService") @Conditional(LinuxCondition.class) public EmailService linuxEmailerService(){ return new LinuxEmailService(); } }
僅有一個bean匹配所需的結果時,自動裝配纔是有效的。若是不只有一個bean可以匹配結果的話,這種歧義性會阻礙spring自動裝配屬性、構造器參數或方法參數。 當確實發生歧義性的時候,spring提供了多種可選方案來解決這樣的問題:1.將可選bean中的某一個設爲首選(Primary)的bean。或者使用限定符(qualifier)來幫助spring將可選bean的範圍縮小到只有一個bean。
經過@ Primary來表達最喜歡的方案。@primary可以與@component組合用在組建掃描的bean上。也能夠與@Bean組合用在java配置的bean聲明中。
@Primary @Component public class OperaSinger implements Singer{ @Override public String sing(String lyrics) { return "I am singing in Bocelli voice: "+lyrics; } }
@Primary @Bean public class OperaSinger implements Singer{ @Override public String sing(String lyrics) { return "I am singing in Bocelli voice: "+lyrics; } }
<bean id ="iceCream" class = "com.dess.IceCream" primary = "true">
@Qualifier 註解是使用限定符的主要方式,能夠與@Autowired 和@Inject協同使用,在注入的時候制定想要注入進去的是那個bean。@qualifier註解所設置的參數就是想要注入的bean的id。
@Autowired @Qualifier("office") private Office office;
建立本身的限定符,所須要作的就是在bean聲明上添加@Qualifier註解。
// @Component @Qualifier("code") private Office office; //顯示定義bean,聲明限定符 @Bean @Qualifier("code") private Office office;
當使用自定義的@qualifier值時,最佳實踐爲bean選擇特徵或描述性的術語,而不是使用隨意的名字
面向特性的限定符要比基於beanID的限定符更好一些。
Spring上下文中全部bean都是做爲單例(singleton)的形式建立的。註解:scope。做用域包括
應用場景:購物車場景。
@Component @Scope ( value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES) public ShoppingCart cart() {...}
@Scope的ProxyMode屬性,它被設置成了ScopedProxyMode.INTERFACES.這個屬性解決了會話或請求做用域的bean注入到單例bean中所遇到的問題。
Spring引入了做用域代理的方法,來解決該問題。代理會暴露與ShoppingCart相同的方法,當StoreService調用ShoppingCart的方法時,代理會對其進行懶解析並將調用委託給會話做用域內的真正的ShoppingCart bean。(即做用域代理可以延遲注入請求和會話做用域的bean)
若是使用XML來聲明會話或請求做用域的bean,除了須要使用<bean>元素的scope屬性設置bean的做用域外,還要使用Spring aop命名空間的aop:scoped-proxy元素。
aop:scoped-proxy是與@Scope註解的proxyMode屬性功能相同的SpringXML配置元素。它會告訴Spring爲bean建立一個做用域代理。默認狀況下,它會使用CGLib建立目標類的代理。(能夠經過將proxy-target-class屬性設置爲false,進而要求生成基於接口的代理),例如
<bean id="cart" class="com.myapp.ShoppingCart" scope="session"> <aop:scoped-proxy/> </bean>
注:上述代碼,聲明做用域爲會話的bean,同時指定代理模式爲建立目標類的方式。
<bean id="cart" class="com.myapp.ShoppingCart" scope="session"> <aop:scoped-proxy proxy-target-class="false" /> </bean>
注:上述代碼,聲明做用域爲會話的bean,同時指定代理模式爲基於接口的方式。
另外,爲了使用aop:scoped-proxy元素,必須在XML配置中聲明Spring的aop命名空間:
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> ... </bean>
運行時注入:是指將一個值注入到bean的屬性或者構造器的參數中。爲了實現這些功能,spring提供了兩種在運行時求值的方式:
處理外部值的最簡單方法就是聲明屬性源並經過Spring的Environment來檢索屬性。
@Configuration //聲明屬性源 @PropertySource("classpath:/com/soundsystem/app.properties") public class ExpressiveConfig { @Autowired Environment env; @Bean public BlankDisc disc() { return new BlankDisc( //檢索屬性值 env.getProperty("disc.title"); env.getProperty("disc.artist")); } }
上述代碼,@PropertySource 引用了類路徑中一個名爲app.properties的文件。該文件內容以下:
disc.title=Sgt. Peppers Lonely Hearts Club Band disc.artist=The Beatles
String getProperty(String key) // 返回String類型的值
String getProperty(String key, String defaultValue) // 指定默認值的版本(當指定的屬性不存在時,會使用一個默認值)
T getProperty(String key, Class<T> type) // 返回指定類型的值
T getProperty(String key, Class<T> type, T defaultValue)
方法: containsProperty()方法:檢查某個屬性是否存在。 getPropertyAsClass()方法:將屬性解析爲類。例如:
Class<CompactDisc> cdClass = env.getPropertyAsClass("disc.class", CompactDisc.class);
除了屬性相關的功能外,Environment還提供了一些方法來檢查哪些profile處於激活狀態:
【】String[] getActiveProfiles() : 返回激活profile名稱的數組
【】String[] getDefaultProfiles() : 返回默認profile名稱的數組
【】boolean acceptsProfiles(String... profiles) : 若是environmet支持給定profile的話,返回true;
(2)、解析屬性佔位符
在Spring裝配中,佔位符的形式爲使用「${...}」包裝的屬性名稱。
若是要在XML中解析構造參數,能夠以下所示:
<bean id="sgtPeppers" class="soundsystem.BlankDisc" c:_title="${disc.title}" c:_title="${disc.artist}" />
若是是依賴組件掃描和自動裝配來建立和初始化組件的話,能夠使用@Value註解,例如:在BlankDisc類中,能夠以下初始化:
public BlankDisc( @Value("${disc.title}") String title, @Value("${disc.artist}") String artist) { this.title = title; this.artist = artist; }
爲了使用佔位符,必須配置一個PropertyPlaceholderConfigurer bean 或PropertySourcesPlaceholderConfigurer bean。(從Spring 3.1開始,推薦使用PropertySourcesPlaceholderConfigurer, 由於它可以基於Spring Environment及其屬性源來解析佔位符)。