ApplicationContext Spring揭秘閱讀總結(jié)

????????作為Spring提供的較之BeanFactory更為先進(jìn)的IoC容器實現(xiàn),ApplicationContext除了擁有BeanFactory支持的所有功能之外饲做,還進(jìn)一步擴展了基本容器的功能飒箭,包括BeanFactoryPostProcessor狼电、BeanPostProcessor以及其他特殊類型bean的自動識別蜒灰、容器啟動后bean實例的自動初始化、國際化的信息支持肩碟、容器內(nèi)事件發(fā)布等卷员。真是“青出于藍(lán)而勝于藍(lán)”啊腾务!

????????Spring為基本的BeanFactory類型容器提供了XmlBeanFactory實現(xiàn)。相應(yīng)地削饵,它也為ApplicationContext類型容器提供了以下幾個常用的實現(xiàn)岩瘦。

? org.springframework.context.support.FileSystemXmlApplicationContext。在默認(rèn)情況下窿撬,從文件系統(tǒng)加載bean定義以及相關(guān)資源的ApplicationContext實現(xiàn)启昧。

? org.springframework.context.support.ClassPathXmlApplicationContext。在默認(rèn)情況下劈伴,從Classpath加載bean定義以及相關(guān)資源的ApplicationContext實現(xiàn)密末。

? org.springframework.web.context.support.XmlWebApplicationContext。Spring提供的用于Web應(yīng)用程序的ApplicationContext實現(xiàn)跛璧,我們將在第六部分更多地接觸到它严里。

????????更多實現(xiàn)可以參照org.springframework.context.ApplicationContext接口定義的Javadoc,這里不再贅述追城。

????????第4章中說明了ApplicationContext所支持的大部分功能刹碾。下面主要圍繞ApplicationContext較之BeanFactory特有的一些特性展開討論,即國際化(I18n)信息支持座柱、統(tǒng)一資源加載策略以及容器內(nèi)事件發(fā)布等迷帜。

5.1 統(tǒng)一資源加載策略

? ??????要搞清楚Spring為什么提供這么一個功能,還是從Java SE提供的標(biāo)準(zhǔn)類java.net.URL說起比較好色洞。URL全名是Uniform Resource Locator(統(tǒng)一資源定位器)戏锹,但多少有些名不副實的味道。

????????首先火诸,說是統(tǒng)一資源定位锦针,但基本實現(xiàn)卻只限于網(wǎng)絡(luò)形式發(fā)布的資源的查找和定位工作,基本上只提供了基于HTTP惭蹂、FTP伞插、File等協(xié)議(sun.net.www.protocol包下所支持的協(xié)議)的資源定位功能。雖然也提供了擴展的接口盾碗,但從一開始媚污,其自身的“定位”就已經(jīng)趨于狹隘了。實際上廷雅,資源這個詞的范圍比較廣義耗美,資源可以任何形式存在京髓,如以二進(jìn)制對象形式存在、以字節(jié)流形式存在商架、以文件形式存在等堰怨;而且,資源也可以存在于任何場所蛇摸,如存在于文件系統(tǒng)备图、存在于Java應(yīng)用的Classpath中,甚至存在于URL可以定位的地方赶袄。

? ??????其次揽涮,從某些程度上來說,該類的功能職責(zé)劃分不清饿肺,資源的查找和資源的表示沒有一個清晰的界限蒋困。當(dāng)前情況是,資源查找后返回的形式多種多樣敬辣,沒有一個統(tǒng)一的抽象雪标。理想情況下,資源查找完成后溉跃,返回給客戶端的應(yīng)該是一個統(tǒng)一的資源抽象接口村刨,客戶端要對資源進(jìn)行什么樣的處理,應(yīng)該由資源抽象接口來界定喊积,而不應(yīng)該成為資源的定位者和查找者同時要關(guān)心的事情烹困。

????????所以,在這個前提下乾吻,Spring提出了一套基于org.springframework.core.io.Resource和org.springframework.core.io.ResourceLoader接口的資源抽象和加載策略髓梅。

5.1.1 Spring中的Resource

????????Spring框架內(nèi)部使用org.springframework.core.io.Resource接口作為所有資源的抽象和訪 問接口,我們之前在構(gòu)造BeanFactory的時候已經(jīng)接觸過它绎签,如下代碼:

????????BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("..."));?

????????其中ClassPathResource就是Resource的一個特定類型的實現(xiàn)枯饿,代表的是位于Classpath中的資源。

????????Resource接口可以根據(jù)資源的不同類型诡必,或者資源所處的不同場合奢方,給出相應(yīng)的具體實現(xiàn)。Spring框架在這個理念的基礎(chǔ)上爸舒,提供了一些實現(xiàn)類(可以在org.springframework.core.io包下找到這些實現(xiàn)類)蟋字。

? ByteArrayResource。將字節(jié)(byte)數(shù)組提供的數(shù)據(jù)作為一種資源進(jìn)行封裝扭勉,如果通過InputStream形式訪問該類型的資源鹊奖,該實現(xiàn)會根據(jù)字節(jié)數(shù)組的數(shù)據(jù),構(gòu)造相應(yīng)的ByteArray-InputStream并返回涂炎。

? ClassPathResource忠聚。該實現(xiàn)從Java應(yīng)用程序的ClassPath中加載具體資源并進(jìn)行封裝设哗,可以使用指定的類加載器(ClassLoader)或者給定的類進(jìn)行資源加載。9

? FileSystemResource两蟀。對java.io.File類型的封裝网梢,所以,我們可以以文件或者URL的形式對該類型資源進(jìn)行訪問赂毯,只要能跟File打的交道战虏,基本上跟FileSystemResource也可以。10

? UrlResource党涕。通過java.net.URL進(jìn)行的具體資源查找定位的實現(xiàn)類活烙,內(nèi)部委派URL進(jìn)行具體的資源操作。11 ? InputStreamResource遣鼓。將給定的InputStream視為一種資源的Resource實現(xiàn)類,較為少用重贺∑锼睿可能的情況下,以ByteArrayResource以及其他形式資源實現(xiàn)代之气笙。

????????如果以上這些資源實現(xiàn)還不能滿足要求次企,那么我們還可以根據(jù)相應(yīng)場景給出自己的實現(xiàn),只需實現(xiàn)org.springframework.core.io.Resource接口就是了潜圃。

5.1.2 ResourceLoader缸棵,“更廣義的URL”

? ??????資源是有了,但如何去查找和定位這些資源谭期,則應(yīng)該是ResourceLoader的職責(zé)所在了堵第。org.springframework.core.io.ResourceLoader接口是資源查找定位策略的統(tǒng)一抽象,具體的資源查找定位策略則由相應(yīng)的ResourceLoader實現(xiàn)類給出隧出。我想踏志,把ResourceLoader稱作統(tǒng)一資源定位器或許才更恰當(dāng)一些吧!ResourceLoader定義如下:

????????其中最主要的就是Resource getResource(String location);方法胀瞪,通過它针余,我們就可以根據(jù)指定的資源位置,定位到具體的資源實例凄诞。

1. 可用的ResourceLoader

? DefaultResourceLoader

????????ResourceLoader有一個默認(rèn)的實現(xiàn)類圆雁,即org.springframework.core.io.DefaultResource-Loader,該類默認(rèn)的資源查找處理邏輯如下帆谍。

(1) 首先檢查資源路徑是否以classpath:前綴打頭伪朽,如果是,則嘗試構(gòu)造ClassPathResource類型資源并返回既忆。

(2) 否則驱负,(a) 嘗試通過URL嗦玖,根據(jù)資源路徑來定位資源,如果沒有拋出MalformedURLException跃脊,有則會構(gòu)造UrlResource類型的資源并返回宇挫;(b)如果還是無法根據(jù)資源路徑定位指定的資源,則委派getResourceByPath(String) 方法來定位酪术, DefaultResourceLoader 的getResourceByPath(String)方法默認(rèn)實現(xiàn)邏輯是器瘪,構(gòu)造ClassPathResource類型的資源并返回。

? FileSystemResourceLoader

????????為了避免DefaultResourceLoader在最后getResourceByPath(String)方法上的不恰當(dāng)處理绘雁,我們可以使用org.springframework.core.io.FileSystemResourceLoader橡疼,它繼承自Default-ResourceLoader,但覆寫了getResourceByPath(String)方法庐舟,使之從文件系統(tǒng)加載資源并以FileSystemResource類型返回欣除。這樣,我們就可以取得預(yù)想的資源類型挪略。代碼清單5-3中的代碼將幫助我們驗證這一點历帚。

????????FileSystemResourceLoader在ResourceLoader家族中的兄弟FileSystemXmlApplication-Context,也是覆寫了getResourceByPath(String)方法的邏輯杠娱,以改變DefaultResourceLoader的默認(rèn)資源加載行為挽牢,最終從文件系統(tǒng)中加載并返回FileSystemResource類型的資源。

2. ResourcePatternResolver——批量查找的ResourceLoader

????????ResourcePatternResolver是ResourceLoader的擴展摊求,ResourceLoader每次只能根據(jù)資源路徑返回確定的單個Resource實例禽拔,而ResourcePatternResolver則可以根據(jù)指定的資源路徑匹配模式,每次返回多個Resource實例室叉。接口org.springframework.core.io.support.ResourcePattern-Resolver定義如下:

3. 回顧與展望

? ??????現(xiàn)在我們應(yīng)該對Spring的統(tǒng)一資源加載策略有了一個整體上的認(rèn)識睹栖,就如圖5-1所示。

5.1.3 ApplicationContext與ResourceLoader

????????ApplicationContext繼承了ResourcePatternResolver茧痕,當(dāng) 然就間接實現(xiàn)了ResourceLoader接口磨淌。所以,任何的ApplicationContext實現(xiàn)都可以看作是一個ResourceLoader甚至ResourcePatternResolver凿渊。而這就是ApplicationContext支持Spring內(nèi)統(tǒng)一資源加載策略的真相梁只。


1. 扮演ResourceLoader的角色

????????既然ApplicationContext可以作為ResourceLoader或者ResourcePatternResolver來使用,那么埃脏,很顯然搪锣,我們可以通過ApplicationContext來加載任何Spring支持的Resource類型。與直接使用ResourceLoader來做這些事情相比彩掐,很明顯构舟,ApplicationContext的表現(xiàn)過于“謙虛”了。

2. ResourceLoader類型的注入

? ??????在大部分情況下堵幽,如果某個bean需要依賴于ResourceLoader來查找定位資源狗超,我們可以為其注入容器中聲明的某個具體的ResourceLoader實現(xiàn)弹澎,該bean也無需實現(xiàn)任何接口,直接通過構(gòu)造方法注入或者setter方法注入規(guī)則聲明依賴即可努咐,這樣處理是比較合理的苦蒿。不過,如果你不介意你的bean定義依賴于Spring的API渗稍,那不妨考慮用一下Spring提供的便利佩迟。

3. Resource類型的注入

????????我們之前講過,容器可以將bean定義文件中的字符串形式表達(dá)的信息竿屹,正確地轉(zhuǎn)換成具體對象定義的依賴類型报强。對于那些Spring容器提供的默認(rèn)的PropertyEditors無法識別的對象類型,我們可以提供自定義的PropertyEditor實現(xiàn)并注冊到容器中拱燃,以供容器做類型轉(zhuǎn)換的時候使用秉溉。

5.2.1 Java SE提供的國際化支持

? ??????對于Java中的國際化信息處理,主要涉及兩個類碗誉,即java.util.Locale和java.util.ResourceBundle坚嗜。

1. Locale

? ??????不同的Locale代表不同的國家和地區(qū),每個國家和地區(qū)在Locale這里都有相應(yīng)的簡寫代碼表示诗充, 包括語言代碼以及國家代碼,這些代碼是ISO標(biāo)準(zhǔn)代碼诱建。如蝴蜓,Locale.CHINA代表中國,它的代碼表示為zh_CN俺猿;Locale.US代表美國地區(qū)茎匠,代碼表示為en_US;而美國和英國等都屬于英語地區(qū)押袍,則可以使用Locale.ENGLISH來統(tǒng)一表示诵冒,這時代碼只有語言代碼,即en谊惭。

2. ResourceBundle

????????ResourceBundle用來保存特定于某個Locale的信息(可以是String類型信息汽馋,也可以是任何類型的對象)。通常圈盔,ResourceBundle管理一組信息序列豹芯,所有的信息序列有統(tǒng)一的一個basename,然后特定的Locale的信息驱敲,可以根據(jù)basename后追加的語言或者地區(qū)代碼來區(qū)分铁蹈。

5.2.2 MessageSource與ApplicationContext

? ??????Spring在Java SE的國際化支持的基礎(chǔ)上,進(jìn)一步抽象了國際化信息的訪問接口众眨,也就是org.springframework.context.MessageSource握牧。通過該接口容诬,我們統(tǒng)一了國際化信息的訪問方式。傳入相應(yīng)的Locale沿腰、資源的鍵以及相應(yīng)參數(shù)览徒,就可以取得相應(yīng)的信息,再也不用先根據(jù)Locale取得ResourceBundle矫俺,然后再從ResourceBundle查詢信息了吱殉。

5.3 容器內(nèi)部事件發(fā)布

????????Spring的ApplicationContext容器提供的容器內(nèi)事件發(fā)布功能,是通過提供一套基于Java SE標(biāo)準(zhǔn)自定義事件類而實現(xiàn)的厘托。為了更好地了解這組自定義事件類友雳,我們可以先從Java SE的標(biāo)準(zhǔn)自定義事件類實現(xiàn)的推薦流程說起。

5.3.1 自定義事件發(fā)布

? ??????Java SE提供了實現(xiàn)自定義事件發(fā)布(Custom Event publication)功能的基礎(chǔ)類铅匹,即java.util.EventObject類和java.util.EventListener接口押赊。所有的自定義事件類型可以通過擴展EventObject來實現(xiàn),而事件的監(jiān)聽器則擴展自EventListener包斑。下面讓我們看一下要實現(xiàn)一套自定義事件發(fā)布類的架構(gòu)流礁,應(yīng)該如何來做。

????????給出自定義事件類型(define your own event object)罗丰。為了針對具體場景可以區(qū)分具體的事件類型神帅,我們需要給出自己的事件類型的定義,通常做法是擴展java.util.EventObject類來實現(xiàn)自定義的事件類型萌抵。

5.3.2 Spring 的容器內(nèi)事件發(fā)布類結(jié)構(gòu)分析

????????Spring 的ApplicationContext 容器內(nèi)部允許以org.springframework.context.ApplicationEvent的形式發(fā)布事件找御, 容器內(nèi)注冊的org.springframework.context.Application-Listener類型的bean定義會被ApplicationContext容器自動識別,它們負(fù)責(zé)監(jiān)聽容器內(nèi)發(fā)布的所有ApplicationEvent類型的事件绍填。也就是說霎桅,一旦容器內(nèi)發(fā)布ApplicationEvent及其子類型的事件,注冊到容器的ApplicationListener就會對這些事件進(jìn)行處理讨永。

5.3.3 Spring 容器內(nèi)事件發(fā)布的應(yīng)用

? ??????Spring的ApplicationContext容器內(nèi)的事件發(fā)布機制滔驶,主要用于單一容器內(nèi)的簡單消息通知和處理,并不適合分布式卿闹、多進(jìn)程揭糕、多容器之間的事件通知。雖然可以通過Spring的Remoting支持锻霎,“曲折一點”來實現(xiàn)較為復(fù)雜的需求插佛,但是難免弊大于利,失大于得量窘。其他消息機制處理較復(fù)雜場景或許更合適雇寇。所以,我們應(yīng)該在合適的地點、合適的需求分析的前提下锨侯,合理地使用Spring提供的ApplicationContext容器內(nèi)的事件發(fā)布機制嫩海。

????????要讓我們的業(yè)務(wù)類支持容器內(nèi)的事件發(fā)布,需要它擁有ApplicationEventPublisher的事件發(fā) 布支持囚痴。所以叁怪,需要為其注入ApplicationEventPublisher實例∩罟觯可以通過如下兩種方式為我們的業(yè)務(wù)對象注入ApplicationEventPublisher的依賴奕谭。

? 使用ApplicationEventPublisherAware接口。在ApplicationContext類型的容器啟動時痴荐,會自動識別該類型的bean定義并將ApplicationContext容器本身作為ApplicationEvent-Publisher注入當(dāng)前對象血柳,而ApplicationContext容器本身就是一個ApplicationEvent-Publisher。

? 使用ApplicationContextAware接口生兆。既然ApplicationContext本身就是一個Application-EventPublisher难捌,那么通過ApplicationContextAware幾乎達(dá)到第一種方式相同的效果。


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸦难,一起剝皮案震驚了整個濱河市根吁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌合蔽,老刑警劉巖击敌,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拴事,居然都是意外死亡沃斤,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門挤聘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捅彻,你說我怎么就攤上這事组去。” “怎么了步淹?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵从隆,是天一觀的道長。 經(jīng)常有香客問我缭裆,道長键闺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任澈驼,我火速辦了婚禮辛燥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己挎塌,他們只是感情好徘六,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著榴都,像睡著了一般待锈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嘴高,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天竿音,我揣著相機與錄音,去河邊找鬼拴驮。 笑死春瞬,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的莹汤。 我是一名探鬼主播快鱼,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼纲岭!你這毒婦竟也來了抹竹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤止潮,失蹤者是張志新(化名)和其女友劉穎窃判,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喇闸,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡袄琳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了燃乍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唆樊。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖刻蟹,靈堂內(nèi)的尸體忽然破棺而出逗旁,到底是詐尸還是另有隱情,我是刑警寧澤舆瘪,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布片效,位于F島的核電站,受9級特大地震影響英古,放射性物質(zhì)發(fā)生泄漏淀衣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一召调、第九天 我趴在偏房一處隱蔽的房頂上張望膨桥。 院中可真熱鬧蛮浑,春花似錦、人聲如沸国撵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽介牙。三九已至壮虫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間环础,已是汗流浹背囚似。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留线得,地道東北人饶唤。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像贯钩,于是被迫代替她去往敵國和親募狂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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