Spring IoC容器之環(huán)境抽象

Environment是一個集成到容器中的特殊抽象兽狭,它針對應(yīng)用環(huán)境建立了profile和properties师郑。

\bullet profile:包含了多個bean定義的一個邏輯集合娃肿,只有當(dāng)指定的profile倍激活時儡蔓,其中的bean才會被激活优床。通過XML定義或通過注解像寒,bean都可以配置到profile中烘豹。Environment與profile相關(guān)聯(lián),然后決定來激活哪個profile或哪個為默認(rèn)的profile诺祸。

\bullet 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ā)大全》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秒咐,一起剝皮案震驚了整個濱河市谬晕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌携取,老刑警劉巖攒钳,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異雷滋,居然都是意外死亡不撑,警方通過查閱死者的電腦和手機(jī)文兢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來焕檬,“玉大人姆坚,你說我怎么就攤上這事∈涤蓿” “怎么了兼呵?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長爆侣。 經(jīng)常有香客問我萍程,道長,這世上最難降的妖魔是什么兔仰? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任茫负,我火速辦了婚禮,結(jié)果婚禮上乎赴,老公的妹妹穿的比我還像新娘只损。我一直安慰自己洲敢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著刽脖,像睡著了一般泵琳。 火紅的嫁衣襯著肌膚如雪袁翁。 梳的紋絲不亂的頭發(fā)上朗鸠,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機(jī)與錄音顽素,去河邊找鬼咽弦。 笑死,一個胖子當(dāng)著我的面吹牛胁出,可吹牛的內(nèi)容都是我干的甲锡。 我是一名探鬼主播携添,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼妹懒,長吁一口氣:“原來是場噩夢啊……” “哼芽卿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起抑淫,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤绷落,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后始苇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嘱函,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年埂蕊,在試婚紗的時候發(fā)現(xiàn)自己被綠了往弓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡蓄氧,死狀恐怖函似,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情喉童,我是刑警寧澤撇寞,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站堂氯,受9級特大地震影響蔑担,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜咽白,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一啤握、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧晶框,春花似錦排抬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至侵贵,卻和暖如春届搁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背窍育。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工卡睦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蔫骂。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓么翰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親辽旋。 傳聞我的和親對象是個殘疾皇子浩嫌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容