關(guān)于<context:property-placeholder>的一個有趣現(xiàn)象

先來看下A和B兩個模塊

A模塊和B模塊都分別擁有自己的Spring XML配置售貌,并分別擁有自己的配置文件:

A模塊

A模塊的Spring配置文件如下:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
   <context:property-placeholder location="classpath*:conf/conf_a.properties"/>
   <bean class="com.xxx.aaa.Bean1"
          p:driverClassName="${modulea.jdbc.driverClassName}"
          p:url="${modulea.jdbc.url}"
          p:username="${modulea.jdbc.username}"
          p:password="${modulea.jdbc.password}"/>
</beans>

其配置文件位于類路徑conf/conf_a.properties中:

modulea.jdbc.driverClassName=com.mysql.jdbc.Driver
modulea.jdbc.username=cartan
modulea.jdbc.password=superman
modulea.jdbc.url=jdbc:mysql://127.0.0.1:3306/modulea?useUnicode=true&characterEncoding=utf8

B模塊

B模塊的Spring配置文件如下:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
   <context:property-placeholder location="classpath*:conf/conf_b.properties"/>
   <bean class="com.xxx.bbb.Bean1"
          p:driverClassName="${moduleb.jdbc.driverClassName}"
          p:url="${moduleb.jdbc.url}"
          p:username="${moduleb.jdbc.username}"
          p:password="${moduleb.jdbc.password}"/>
</beans>

其配置文件位于類路徑conf/conf_b.properties中:

moduleb.jdbc.driverClassName=com.mysql.jdbc.Driver
moduleb.jdbc.username=cartan
moduleb.jdbc.password=superman
moduleb.jdbc.url=jdbc:mysql://127.0.0.1:3306/modulea?useUnicode=true&characterEncoding=utf8

問題來了

單獨運行A模塊漆弄,或單獨運行B模塊都是正常的,但將A和B兩個模塊集成后運行,Spring容器就啟動不了了:

Could not resolve placeholder 'moduleb.jdbc.driverClassName' in string value "${moduleb.jdbc.driverClassName}"[/quote]

到底出了啥問題

隨便搜索了一下,還發(fā)現(xiàn)很多人遇到這個問題,這個就是來自stackoverflow的問題:
http://stackoverflow.com/questions/7940452/spring-application-context-not-able-to-load-property-placeholder-properties

可惜啊,好像都沒有人給出正確的解決梦谜。

那究竟是什么問題呢?也想了很久哦....終于回想起來了(寫書時讀過Spring源碼)袭景,原來是Spring容器采用反射掃描的發(fā)現(xiàn)機(jī)制唁桩,在探測到Spring容器中有一個org.springframework.beans.factory.config.PropertyPlaceholderConfigurer的Bean就會停止對剩余PropertyPlaceholderConfigurer的掃描(Spring 3.1已經(jīng)使用PropertySourcesPlaceholderConfigurer替代PropertyPlaceholderConfigurer了)。

<context:property-placeholder/>這個基于命名空間的配置耸棒,其實內(nèi)部就是創(chuàng)建一個PropertyPlaceholderConfigurer Bean而已朵夏。換句話說,即Spring容器僅允許最多定義一個PropertyPlaceholderConfigurer(或<context:property-placeholder/>)榆纽,其余的會被Spring忽略掉(其實Spring如果提供一個警告就好了)仰猖。

拿上來的例子來說,如果A和B模塊是單獨運行的奈籽,由于Spring容器都只有一個PropertyPlaceholderConfigurer饥侵,因此屬性文件會被正常加載并替換掉。如果A和B兩模塊集成后運行衣屏,Spring容器中就有兩個PropertyPlaceholderConfigurer Bean了躏升,這時就看誰先誰后了, 先的保留狼忱,后的忽略膨疏!因此,只加載到了一個屬性文件钻弄,因而造成無法正確進(jìn)行屬性替換的問題佃却。

咋解決呢?

定位問題需要9999元錢窘俺,解決問題只需要1元錢 :D 饲帅。
屬性文件加載在統(tǒng)一的地方做,不要分模塊加載即可瘤泪。

A模塊a.xml:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
   <!--<context:property-placeholder location="classpath*:conf/conf_a.properties"/>-->
   <bean class="com.xxx.aaa.Bean1"
          p:driverClassName="${modulea.jdbc.driverClassName}"
          p:url="${modulea.jdbc.url}"
          p:username="${modulea.jdbc.username}"
          p:password="${modulea.jdbc.password}"/>
</beans>

B模塊b.xml:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
   <!--<context:property-placeholder location="classpath*:conf/conf_b.properties"/>-->
   <bean class="com.xxx.bbb.Bean1"
          p:driverClassName="${moduleb.jdbc.driverClassName}"
          p:url="${moduleb.jdbc.url}"
          p:username="${moduleb.jdbc.username}"
          p:password="${moduleb.jdbc.password}"/>
</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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
   <context:property-placeholder location="classpath*:conf/conf*.properties"/>
   <import resource="a.xml"/>
   <import resource="b.xml"/>
</beans>

進(jìn)一步思考

為什么霸畋谩?Spring為什么要這樣呢对途?細(xì)想想是有道理的赦邻,一個項目或一個系統(tǒng)的配置應(yīng)該放在一起,不宜分散实檀。
這樣才可以做到統(tǒng)一管控惶洲,否則到處都有配置按声,到底是加載哪個配置文件呢?有時你還會不小心讓JAR中的Spring配置文件加載一個位于JAR中的屬性文件湃鹊,而外面有更改不了儒喊。如果Spring使用了這種機(jī)制镣奋,即使JAR包中的Spring配置文件使用<context:property-placeholder/>引用到JAR中的屬性文件币呵,只要你要外而的Spring配置文件中顯示提供一個<context:property-placeholder/>指定另一個屬性文件 ,就可以覆蓋JAR中的默認(rèn)配置了侨颈。

想了一想余赢,Spring這樣做是利大于弊的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末哈垢,一起剝皮案震驚了整個濱河市妻柒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌耘分,老刑警劉巖举塔,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異求泰,居然都是意外死亡央渣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門渴频,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芽丹,“玉大人,你說我怎么就攤上這事卜朗“蔚冢” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵场钉,是天一觀的道長蚊俺。 經(jīng)常有香客問我,道長逛万,這世上最難降的妖魔是什么春叫? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮泣港,結(jié)果婚禮上暂殖,老公的妹妹穿的比我還像新娘。我一直安慰自己当纱,他們只是感情好呛每,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坡氯,像睡著了一般晨横。 火紅的嫁衣襯著肌膚如雪洋腮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天手形,我揣著相機(jī)與錄音啥供,去河邊找鬼。 笑死库糠,一個胖子當(dāng)著我的面吹牛伙狐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瞬欧,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼贷屎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了艘虎?” 一聲冷哼從身側(cè)響起唉侄,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎野建,沒想到半個月后属划,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡候生,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年同眯,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片陶舞。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡嗽测,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肿孵,到底是詐尸還是另有隱情唠粥,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布停做,位于F島的核電站晤愧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蛉腌。R本人自食惡果不足惜官份,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望烙丛。 院中可真熱鬧舅巷,春花似錦、人聲如沸河咽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽忘蟹。三九已至飒房,卻和暖如春搁凸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背狠毯。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工护糖, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嚼松。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓嫡良,卻偏偏與公主長得像,于是被迫代替她去往敵國和親惜颇。 傳聞我的和親對象是個殘疾皇子皆刺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348