Environment是一個集成到容器中的特殊抽象兽狭,它針對應(yīng)用環(huán)境建立了profile和properties师郑。
profile:包含了多個bean定義的一個邏輯集合娃肿,只有當(dāng)指定的profile倍激活時儡蔓,其中的bean才會被激活优床。通過XML定義或通過注解像寒,bean都可以配置到profile中烘豹。Environment與profile相關(guān)聯(lián),然后決定來激活哪個profile或哪個為默認(rèn)的profile诺祸。
properties:它在應(yīng)用中有著重要作用携悯,如property文件、JVM系統(tǒng)的property筷笨、系統(tǒng)環(huán)境變量憔鬼、JNDI龟劲、srevlet上下文參數(shù)、Map等逊彭。Environment與property相關(guān)聯(lián)咸灿,給開發(fā)者一個方便的服務(wù)接口來配置這些數(shù)據(jù)源,并正確解析侮叮。
1避矢、bean定義的profile
在容器中bean定義的profile是一種允許不同環(huán)境注冊不同的bean的機(jī)制,適用以下場景:
1)解決內(nèi)存中數(shù)據(jù)源問題囊榜,可以在不同環(huán)境中訪問不同的數(shù)據(jù)源审胸,如dev、sit卸勺、pre砂沛、prd環(huán)境等。
2)僅在開發(fā)環(huán)境中使用一些監(jiān)視服務(wù)曙求。
3)在不同環(huán)境中使用不同的bean實(shí)現(xiàn)碍庵。
如果泛化了一些特殊環(huán)境下引用的bean定義,可以將其中指定的bean注入特定的上下文中悟狱,而不是注入所有的上下文中静浴。
2、@Profile
@Profile注解允許開發(fā)者表示一個組件是否適合在當(dāng)前環(huán)境下進(jìn)行注冊挤渐,只有當(dāng)前的profile被激活時苹享,對應(yīng)的bean才會被注冊到上下文中。
@Configuration
@Profile("dev")
public class DataConfig {
? ??@Bean
? ? public?DataSource?dataSource() {
? ? ? ? return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
? ? ? ? ? ? .addScript("classpath:com/config/sql/schema.sql")
? ??????????.addScript("classpath:com/config/sql/test-data.sql").build();
????}
}
@Configuration
@Profile("prd")
public class JndiDataConfig {
? ??@Bean
? ??public DataSource dataSource() throws Exception {
? ??????Context ctx =new InitialContext();
????????return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
? ? }
}
@Profile注解可以作為元注解來使用浴麻,如下自定義的@Prd注解可以替代@Profile("prd"):
@Profile注解也可以在方法級別使用得问,還可以聲明在包含@Bean注解的方法上。如下:
@Configuration
public class AppConfig {
????@Bean
? ??@Profile("dev")
? ? public?DataSource?dataSource() {
????????return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
????????????.addScript("classpath:com/config/sql/schema.sql")
????????????.addScript("classpath:com/config/sql/test-data.sql").build();
????}
????@Bean
????@Profile("prd")
????public DataSource dataSource() throws Exception {
????????Context ctx =new InitialContext();
????????return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
????}
}
如果配置了@Configuration的類同時也配置了@profile软免,則所有配置了@Bean注解的方法和@Import注解的類都會被傳遞為該profile宫纬。除非這個profile被激活,否則其中的bean定義都不會被激活膏萧。如果配置為@Component或@Configuration的類標(biāo)記了@profile({"p1","p2"})哪怔,那么這個類當(dāng)且僅當(dāng)profile為p1或p2時才會被激活。如果某個profile的前綴為“!”向抢,則@profile注解的類只有在當(dāng)前的profile沒被激活時才能生效。如配置為@profile({"p1","!p2"})則注冊的行為會在profile為p1或profile為非p2時被激活胚委。
3挟鸠、XML中定義的profile
在XML中配置<beans/>的profile屬性。
<beans?profile="dev"
????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:jdbc="http://www.springframework.org/schema/jdbc"
? ? xsi:schemaLocation="...">
? ? <jdbc:embedded-database id="dataSource">
? ? ? ? <jdbc:script location="classpath:com/config/sql/schema.sql">
? ??????<jdbc:script location="classpath:com/config/sql/test-data.sql">
? ??</jdbc:embedded-database>
</beans>
<beans?profile="prd"
????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:jee="http://www.springframework.org/schema/jee"
? ? xsi:schemaLocation="...">
? ? <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource" />
</beans>
或者通過嵌套<beans>標(biāo)簽來定義:
<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:jee="http://www.springframework.org/schema/jee"
????xmlns:jdbc="http://www.springframework.org/schema/jdbc"
? ? xsi:schemaLocation="...">
? ??<beans?profile="dev">
? ? ? ? <jdbc:embedded-database id="dataSource">
? ??????????<jdbc:script location="classpath:com/config/sql/schema.sql">
? ??????????<jdbc:script location="classpath:com/config/sql/test-data.sql">
? ??????</jdbc:embedded-database>
? ??</beans>
? ??<beans?profile="prd">
? ??????<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource" />
? ??</beans>
</beans>
4亩冬、激活profile
有多種方法來激活一個profile艘希,最直接的方式是通過編程的方式來直接調(diào)用Environment API硼身。ApplicationContext中包含以下接口:
AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("dev");
context.register(SomeConfig.class,DataConfig.class,PrdDataConfig.class);
context.refresh();
profile還可以通過spring.profiles.active中的屬性來指定,可以通過系統(tǒng)環(huán)境變量覆享、JVM系統(tǒng)變量佳遂、servlet上下文中的參數(shù)或JNDI的一個參數(shù)來寫入。profile的定義并非是互斥關(guān)系撒顿,開發(fā)者可以在同一時間激活多個profile丑罪。
context.getEnvironment().setActiveProfiles("dev","sit");
也可以通過spring.profiles.active來指定逗號分隔的多個profile名稱。
-Dspring.profiles.active=“profile1,profile2”
5凤壁、默認(rèn)profile
@Configuration
@Profile("default")
public class DataConfig {
????@Bean
? ? public?DataSource?dataSource() {
????????return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
????????????.addScript("classpath:com/config/sql/schema.sql")
????????????.addScript("classpath:com/config/sql/test-data.sql").build();
????}
}
如果沒有其他profile被激活吩屹,則以上定義的dataSource將被創(chuàng)建,這種方式是默認(rèn)情況下提供bean定義的一種方式拧抖。一旦任何一個profile被激活煤搜,默認(rèn)的profile將不會被激活。默認(rèn)的profile的名稱可以通過Environment中的setActiveProfiles()或通過spring.profiles.default屬性來更改唧席。
6擦盾、@PropertySource
@PropertySource注解提供了一種方便的機(jī)制將PropertySource添加到spring的Environment中。給定一個文件app.properties包含了key-value對testbean.name=myTestBean淌哟,以下代碼使用@PropertySource調(diào)用testbean.setName()將返回myTestBean迹卢。
@Configuration
@PropertySource("classpath:/com/xlws/app.properties")
public class AppConfig {
? ??@Autowired
? ??Environment env;
? ??@Bean
? ??public?TestBean?testBean() {
? ??????TestBean?testBean = new?TestBean();
? ??????testBean.setName(env.getProperty("testbean.name"));
? ? ? ? return?testBean;
????}
}
任何@PropertySource注解中如${...}的占位符,都可以被解析為Environment中的屬性資源绞绒。如下:
@Configuration
@PropertySource("classpath:/com/ ${my.placeholder:default/path}/app.properties")
public class AppConfig {
????@Autowired
????Environment env;
????@Bean
? ??public?TestBean?testBean() {
????????TestBean?testBean = new?TestBean();
????????testBean.setName(env.getProperty("testbean.name"));
????????return?testBean;
????}
}
假設(shè)my.placeholder是已經(jīng)注冊到Environment中的資源婶希,若有JVM系統(tǒng)屬性或環(huán)境變量,占位符會解析成對象的值蓬衡,若沒有則default/path會作為默認(rèn)值喻杈。如果沒有指定默認(rèn)值,并且占位符也解析不出來狰晚,將會拋出異常IllegalArgumentException筒饰。
7、占位符解析
開發(fā)者可以任意配置占位符:
1)可以自由調(diào)整系統(tǒng)變量和環(huán)境變量的優(yōu)先級壁晒。
2)可以額外增加自己的屬性源信息瓷们。
以下XML配置不關(guān)心customer屬性在哪里定義,只要這個值在Environment中有效即可:
<beans>
? ? <import resource="com/xlws/service/${customer}-config.xml" />
</beans>
--參考文獻(xiàn)《Srping5開發(fā)大全》