Spring高級(jí)配置之運(yùn)行時(shí)注入

之前,我們?cè)O(shè)置Bean的屬性值時(shí),采用的都是硬編碼的形式。比如,在定義BlankDisc時(shí):

@Bean
public BlankDisc blankDisc(){
    
    return new BlankDisc("This is BlankDisc", "The Beatles");
}
 

與之類似,采用XML的方式也是硬編碼:

<bean id = "blankDisc" class = "com.inject.service.BlankDisc"
c:_title = "This id BlankDisc"
c:_artist = "This Beatles" />     

硬編碼的壞處想必大家都知道,所以我們就想能不能讓這些值在程序運(yùn)行時(shí)再確定。其實(shí)Spring已經(jīng)提供了兩種方式實(shí)現(xiàn)運(yùn)行時(shí)注入的功能:

  • 屬性占位符(Property planceholder)
  • Spring 表達(dá)式語(yǔ)言(SpEL)

1.使用屬性占位符注入外部的值

@Autowired
Environment env;

public BlankDisc blanKDiscBean2(){
    return new BlankDisc(
            env.getProperty("disc.title"),
            env.getProperty("disc.artist"));
}

1.1深入學(xué)習(xí)Spring的Environment

Environment的getProperty()方法有四個(gè)重載方法:

  • String getProperty(String key)
  • String getProperty(String key,String defaultValue)
  • T getProperty(String key, Class<T> type)
  • T getProperty(String key, Class<T> type,T defaultValue)

前兩種形式的getProperty()方法都是返回String類型的值。后兩種重載方法不是直接返回字符串,而是將獲取到的值轉(zhuǎn)化為指定類型的值,比如獲取連接池中維持連接的總數(shù)量:

int connectionCount = env.getProperty("db.connoctionCount",Integer.class,30);

在使用getProperty()獲取屬性時(shí),如果這個(gè)屬性沒(méi)有定義,那他獲取的是null,如果我們不想讓這樣的情況發(fā)生,可以使用getRequiredProperty()方法:

//必須定義參數(shù)
env.getRequiredProperty("disc.title"),
env.getRequiredProperty("disc.artist"));

如果disc.title或disc.arist沒(méi)有定義的話,將會(huì)拋出IllegalStateException異常。
如果你想檢查某個(gè)屬性是否存在,那么可以調(diào)用containsProperty()方法:

boolean titleExists = env.containsProperty(“disc.title”);

如果你想將屬性解析為類的話,可以使用getPropertyAsClass()方法:

Class<BlankDisc> blankDisc = env.getPropertyAsClass("disc.class",BlankDisc.class);

除了屬性相關(guān)的功能外,Environment還提供了一些方法來(lái)檢查哪些profile處于激活狀態(tài):

  • String [] getActiveProfiles():返回激活profile名稱的數(shù)組;
  • String [] getDefaultProfile():返回默認(rèn)profile名稱的數(shù)組;
  • boolean acceptsPrifiles(String ... profiles):如果environment支持給定的profile返回true。

1.2解析屬性占位符

在Spring裝配中,占位符的形式為“${...}”包裝的屬性名稱。下面我們使用屬性占位符在XML中解析tomcat連接池bean的屬性:

    <!-- 數(shù)據(jù)源配置, 使用Tomcat JDBC連接池 -->
    <bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
        <!-- Connection Info -->
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>

        <!-- Connection Pooling Info -->
        <property name="maxActive" value="${jdbc.pool.maxActive}"/>
        <property name="maxIdle" value="${jdbc.pool.maxIdle}"/>
    </bean>

要使用占位符,需要配置PropertySourcesPlaceholderConfigurer bean:

@Bean
public static PropertySourcesPlaceholderConfigurer placehoderConfigurer(){
    
    return new PropertySourcesPlaceholderConfigurer();
}

在Xml配置要使用到命名空間中的<context:property-placeholder>元素,它可以為我們生成PropertySourcesPlaceholderConfigurer bean:

<context:property-placeholder ignore-unresolvable="true"
                   location="classpath*:/application.properties,
                   classpath*:/application.local.properties" file-encoding="UTF-8"/>

2.使用Spring表達(dá)式語(yǔ)言進(jìn)行配置

Spring 3引入了Spring表達(dá)式(Spring Excpression Language,SpEL),他能夠以一種強(qiáng)大和簡(jiǎn)潔的方式將值裝配到bean屬性和構(gòu)造器參數(shù)中,這個(gè)過(guò)程中所使用的表達(dá)式會(huì)在運(yùn)行時(shí)計(jì)算得到值。SpEL的特性有以下幾點(diǎn):

  • 使用bean的ID來(lái)引用bean
  • 調(diào)用方法和訪問(wèn)對(duì)象的屬性
  • 對(duì)值進(jìn)行算術(shù)、關(guān)系和邏輯運(yùn)算
  • 正則表達(dá)式匹配
  • 集合操作

2.1SpEl表達(dá)式樣例

格式 說(shuō)明
#{1} 得到的值就是1
#{T(System).currentTimeMillis() 獲取當(dāng)前時(shí)間的毫秒值,T()表達(dá)式會(huì)將java.lang.System視為java中對(duì)應(yīng)的類型,通過(guò).方法調(diào)用對(duì)應(yīng)的靜態(tài)方法
#{blankDisc.title} 獲取ID為blankDisc bean的屬性值
#{systemPropertys['disc.title']} 通過(guò)systemPropertys對(duì)象引用系統(tǒng)屬性

上面幾個(gè)只是幾個(gè)基本的SpEl樣例,后面我們會(huì)著重介紹,下面我們先看看使用SpEL表達(dá)式裝配bean的屬性:

public BlankDisc(
            @Value("#{systemPropertys['disc.title']}") String title, 
            @Value("#{systemPropertys['disc.artist']}") String artist){
        this.title = title;
        this.artist = artist;
    }

上例中使用到@Value注解,在注解中設(shè)置SpEL表達(dá)式。上面我們學(xué)習(xí)了幾個(gè)簡(jiǎn)單的樣例,也學(xué)習(xí)了如何將SpEL表達(dá)式解析得到的值注入到bean中,那么我們來(lái)繼續(xù)學(xué)習(xí)一下SpEl表達(dá)式支持的基礎(chǔ)表達(dá)式吧。

2.2表示字面值

使用SpEL字面量樣式可以表示整數(shù)、浮點(diǎn)數(shù)、String以及Boolean類型的值:

#{1}
#{3.14159}
#{9.87E4}
#{'Hello'}
#{false}

2.3引入bean屬性和方法

SpEL能夠通過(guò)ID引入其他的bean、bean的屬性和bean的方法:

#{blankDisc}
#{blankDisc.title}
#{blankDisc.sayHello()}

如果還可以對(duì)方法的返回值做處理,直接調(diào)用返回值類型的屬性或方法,假設(shè)sayHello()返回值是String類型:#{blankDisc.sayHello().toUpperCase()},這樣就可以獲取返回值的大寫(xiě)字母形式。
但如果返回值是null,調(diào)用它的方法就會(huì)報(bào)空指針異常,為了預(yù)防這種情況,可以使用 ? 判斷獲得返回值是否為null:#{blankDisc.sayHello()?.toUpperCase()}如果sayHello()方法返回值是null,SpEl將不會(huì)調(diào)用toUpperCase()方法,SpEL的返回值是null。

2.4在表達(dá)式中使用類型

如果SpEL表達(dá)式訪問(wèn)類作用域的方法或常量時(shí),要使用到T()這個(gè)關(guān)鍵的運(yùn)算符:#{T(java.lang.Math)}運(yùn)算符的結(jié)果是一個(gè)Class對(duì)象,它代表了java.lang.Math。通過(guò)它我們可以訪問(wèn)Math的靜態(tài)方法和常量。

#{T(java.lang.Math).PI}
#{T(java.lang.Math).random()}

2.5SpEL運(yùn)算符

SpEL提供了多個(gè)運(yùn)算符,這些運(yùn)算符可以使用到SpEL表達(dá)式上:

運(yùn)算符類型 運(yùn)算符
算術(shù)運(yùn)算符 +、- 、*、/ 、%、^
比較運(yùn)算符 <、>、 = 、<=、 >=、 lt、 gt、 eq、 ge
條件運(yùn)算符 ?:(ternary)、 ?:(Elvis)
邏輯運(yùn)算符 and、 or、not、
正則表達(dá)式 matches

2.6計(jì)算正則表達(dá)式

SpEL通過(guò)matches運(yùn)算符支持表達(dá)式中的模式匹配,匹配成功返回true,否則否則返回false,下面我們判斷郵箱是否符合正則表達(dá)式:

#{admin.email matches '[a-zA-Z0-9.-%+-]+@[a-zA-Z0-9.-]+\\.com'}

2.7計(jì)算集合

使用SpEL引用列表中的一個(gè)元素:#{jubox.songs[4].title},獲取列表的第5個(gè)元素(基于0開(kāi)始),[] 是從集合或數(shù)組中按照索引取元素。
SpEL提供了查詢運(yùn)算符(.?[]),他會(huì)用來(lái)對(duì)集合進(jìn)行過(guò)濾,得到集合的一個(gè)子集。下面我們將Aerosmith的歌曲過(guò)濾出來(lái):

#{jukebox.songs.?[artist eq 'Aerosmith']}

.^[]查詢第一個(gè)匹配項(xiàng)
.$[]查詢最后一個(gè)匹配項(xiàng)

投影運(yùn)算符(.![]),將集合對(duì)象特定的字段投影到另一個(gè)集合中,下面我們將歌曲的名稱投影到另一個(gè)String類型的集合中:

#{jukebox.songs.![title]}

我們還可以過(guò)濾要投影的歌曲,下面我們獲取Aerosmith歌曲的title:

#{jukebox.songs.?[artist eq 'Aerosmith'.![title]]}

自此運(yùn)行時(shí)注入的全部?jī)?nèi)容已經(jīng)全部介紹完啦。終于完了啦,下個(gè)月我們開(kāi)始學(xué)習(xí)Spring的Aop機(jī)制,很期待吧,come on!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評(píng)論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,489評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,290評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,776評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,510評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,866評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評(píng)論 3 447
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,036評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,585評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,331評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,536評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,754評(píng)論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,154評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,469評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,273評(píng)論 3 399
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,505評(píng)論 2 379

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,826評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,922評(píng)論 6 342
  • 本章內(nèi)容: Spring profile 條件化的bean聲明 自動(dòng)裝配與歧義性 bean的作用域 Spring表...
    謝隨安閱讀 1,201評(píng)論 0 5
  • “近朱者赤,近墨者黑”,“孟母三遷”,“蓬生麻中,不扶自直”,這些成語(yǔ)都像我們闡釋了一個(gè)道理——朋友圈對(duì)一個(gè)人的成...
    英語(yǔ)老師Audrey閱讀 1,563評(píng)論 3 43
  • 今天跟老公聊天聊到了一個(gè)現(xiàn)象。這次我和孩子們回老家十多天,剛開(kāi)始老公還以為他會(huì)有很多精彩的安排,結(jié)果后來(lái)也發(fā)現(xiàn)自己...
    敏敏52閱讀 389評(píng)論 0 0