Spring之旅

Spring的使命

Spring是一個(gè)開源框架问顷,最早由Rod Johnson創(chuàng)建噪奄,并在《Expert Oneon-One:J2EE Design and Development》這本著作中進(jìn)行了介紹。
Spring最根本的使命是解決企業(yè)級(jí)應(yīng)用開發(fā)的復(fù)雜性,即簡(jiǎn)化Java開發(fā)

Spring可以做很多事情,它為企業(yè)級(jí)開發(fā)提供給了豐富的功能酝锅,但是這些功能的底層都依賴于它的兩個(gè)核心特性,也就是依賴注入(dependency injection奢方,DI)面向切面編程(aspect-oriented programming搔扁,AOP)

為了降低Java開發(fā)的復(fù)雜性袱巨,Spring采取了以下4種關(guān)鍵策略:

  • 基于POJO的輕量級(jí)和最小侵入性編程阁谆;
  • 通過依賴注入和面向接口實(shí)現(xiàn)松耦合;
  • 基于切面和慣例進(jìn)行聲明式編程愉老;
  • 通過切面和模板減少樣板式代碼场绿。

激發(fā)POJO的潛能

很多框架通過強(qiáng)迫應(yīng)用繼承它們的類或?qū)崿F(xiàn)它們的接口從而導(dǎo)致應(yīng)用與框架綁死。一個(gè)典型的例子是EJB 2時(shí)代的無狀態(tài)會(huì)話bean嫉入。早期的EJB是一個(gè)很容易想到的例子焰盗,不過這種侵入式的編程方式在早期版本的Struts、WebWork咒林、Tapestry以及無數(shù)其他的Java規(guī)范和框架中都能看到熬拒。

Spring竭力避免因自身的API而弄亂你的應(yīng)用代碼。Spring不會(huì)強(qiáng)迫你實(shí)現(xiàn)Spring規(guī)范的接口或繼承Spring規(guī)范的類垫竞,相反澎粟,在基于Spring構(gòu)建的應(yīng)用中,它的類通常沒有任何痕跡表明你使用了Spring欢瞪。最壞的場(chǎng)景是活烙,一個(gè)類或許會(huì)使用Spring注解,但它依舊是POJO遣鼓。

Spring的非侵入編程模型意味著這個(gè)類在Spring應(yīng)用和非Spring應(yīng)用中都可以發(fā)揮同樣的作用啸盏。

依賴注入

耦合具有兩面性(two-headed beast)。一方面骑祟,緊密耦合的代碼難以測(cè)試回懦、難以復(fù)用气笙、難以理解,并且典型地表現(xiàn)出“打地鼠”式的bug特性(修復(fù)一個(gè)bug怯晕,將會(huì)出現(xiàn)一個(gè)或者更多新的bug)潜圃。另一方面,一定程度的耦合又是必須的——完全沒有耦合的代碼什么也做不了舟茶。為了完成有實(shí)際意義的功能秉犹,不同的類必須以適當(dāng)?shù)姆绞竭M(jìn)行交互≈赏恚總而言之,耦合是必須的型诚,但應(yīng)當(dāng)被小心謹(jǐn)慎地管理客燕。

通過DI,對(duì)象的依賴關(guān)系將由系統(tǒng)中負(fù)責(zé)協(xié)調(diào)各對(duì)象的第三方組件在創(chuàng)建對(duì)象的時(shí)候進(jìn)行設(shè)定狰贯。對(duì)象無需自行創(chuàng)建或管理它們的依賴關(guān)系也搓,如下圖所示,依賴關(guān)系將被自動(dòng)注入到需要它們的對(duì)象當(dāng)中去涵紊。

依賴注入

依賴注入會(huì)將所依賴的關(guān)系自動(dòng)交給目標(biāo)對(duì)象傍妒,而不是讓對(duì)象自己去獲取依賴。

創(chuàng)建應(yīng)用組件之間協(xié)作的行為通常稱為裝配(wiring)摸柄。Spring有多種裝配bean的方式颤练,采用XML是很常見的一種裝配方式。如果XML配置不符合你的喜好的話驱负,Spring還支持使用Java來描述配置嗦玖。

Spring通過應(yīng)用上下文(Application Context)裝載bean的定義并把它們組裝起來。Spring應(yīng)用上下文全權(quán)負(fù)責(zé)對(duì)象的創(chuàng)建和組裝跃脊。Spring自帶了多種應(yīng)用上下文的實(shí)現(xiàn)宇挫,它們之間主要的區(qū)別僅僅在于如何加載配置。

面向切面編程

DI能夠讓相互協(xié)作的軟件組件保持松散耦合酪术,而面向切面編程(aspect-oriented programming器瘪,AOP)允許你把遍布應(yīng)用各處的功能分離出來形成可重用的組件。

面向切面編程往往被定義為促使軟件系統(tǒng)實(shí)現(xiàn)關(guān)注點(diǎn)的分離一項(xiàng)技術(shù)绘雁。系統(tǒng)由許多不同的組件組成橡疼,每一個(gè)組件各負(fù)責(zé)一塊特定功能。除了實(shí)現(xiàn)自身核心的功能之外咧七,這些組件還經(jīng)常承擔(dān)著額外的職責(zé)衰齐。諸如日志、事務(wù)管理和安全這樣的系統(tǒng)服務(wù)經(jīng)常融入到自身具有核心業(yè)務(wù)邏輯的組件中去继阻,這些系統(tǒng)服務(wù)通常被稱為橫切關(guān)注點(diǎn)耻涛,因?yàn)樗鼈儠?huì)跨越系統(tǒng)的多個(gè)組件废酷。

如果將這些關(guān)注點(diǎn)分散到多個(gè)組件中去,你的代碼將會(huì)帶來雙重的復(fù)雜性抹缕。

  • 實(shí)現(xiàn)系統(tǒng)關(guān)注點(diǎn)功能的代碼將會(huì)重復(fù)出現(xiàn)在多個(gè)組件中澈蟆。這意味著如果你要改變這些關(guān)注點(diǎn)的邏輯,必須修改各個(gè)模塊中的相關(guān)實(shí)現(xiàn)卓研。即使你把這些關(guān)注點(diǎn)抽象為一個(gè)獨(dú)立的模塊趴俘,其他模塊只是調(diào)用它的方法,但方法的調(diào)用還是會(huì)重復(fù)出現(xiàn)在各個(gè)模塊中奏赘。
  • 組件會(huì)因?yàn)槟切┡c自身核心業(yè)務(wù)無關(guān)的代碼而變得混亂寥闪。一個(gè)向地址簿增加地址條目的方法應(yīng)該只關(guān)注如何添加地址,而不應(yīng)該關(guān)注它是不是安全的或者是否需要支持事務(wù)磨淌。
關(guān)注點(diǎn)的調(diào)用散布到各個(gè)模塊

在整個(gè)系統(tǒng)內(nèi)疲憋,關(guān)注點(diǎn)(例如日志和安全)的調(diào)用經(jīng)常散布到各個(gè)模塊中,而這些關(guān)注點(diǎn)并不是模塊的核心業(yè)務(wù)梁只。

AOP能夠使這些服務(wù)模塊化缚柳,并以聲明的方式將它們應(yīng)用到它們需要影響的組件中去。所造成的結(jié)果就是這些組件會(huì)具有更高的內(nèi)聚性并且會(huì)更加關(guān)注自身的業(yè)務(wù)搪锣,完全不需要了解涉及系統(tǒng)服務(wù)所帶來復(fù)雜性秋忙。總之构舟,AOP能夠確保POJO的簡(jiǎn)單性灰追。

如下圖所示,我們可以把切面想象為覆蓋在很多組件之上的一個(gè)外殼狗超。應(yīng)用是由那些實(shí)現(xiàn)各自業(yè)務(wù)功能的模塊組成的监嗜。借助AOP,可以使用各種功能層去包裹核心業(yè)務(wù)層抡谐。這些層以聲明的方式靈活地應(yīng)用到系統(tǒng)中裁奇,你的核心應(yīng)用甚至根本不知道它們的存在。這是一個(gè)非常強(qiáng)大的理念麦撵,可以將安全刽肠、事務(wù)和日志關(guān)注點(diǎn)與核心業(yè)務(wù)邏輯相分
離。

關(guān)注點(diǎn)覆蓋所影響的組件

使用模板消除樣板式代碼

你是否寫過這樣的代碼免胃,當(dāng)編寫的時(shí)候總會(huì)感覺以前曾經(jīng)這么寫過音五?我的朋友,這不是似曾相識(shí)羔沙。這是樣板式的代碼(boilerplate code)躺涝。通常為了實(shí)現(xiàn)通用的和簡(jiǎn)單的任務(wù),你不得不一遍遍地重復(fù)編寫這樣的代碼扼雏。

遺憾的是坚嗜,它們中的很多是因?yàn)槭褂肑ava API而導(dǎo)致的樣板式代碼夯膀。樣板式代碼的一個(gè)常見范例是使用JDBC訪問數(shù)據(jù)庫(kù)查詢數(shù)據(jù)。

Spring旨在通過模板封裝來消除樣板式代碼苍蔬。

容納你的Bean

在基于Spring的應(yīng)用中诱建,你的應(yīng)用對(duì)象生存于Spring容器(container)中。Spring容器負(fù)責(zé)創(chuàng)建對(duì)象碟绑,裝配它們俺猿,配置它們并管理它們的整個(gè)生命周期,從生存到死亡(在這里格仲,可能就是new到finalize())押袍。

容器是Spring框架的核心。Spring容器使用DI管理構(gòu)成應(yīng)用的組件凯肋,它會(huì)創(chuàng)建相互協(xié)作的組件之間的關(guān)聯(lián)伯病。毫無疑問,這些對(duì)象更簡(jiǎn)單干凈否过,更易于理解,更易于重用并且更易于進(jìn)行單元測(cè)試惭蟋。

Spring容器并不是只有一個(gè)苗桂。Spring自帶了多個(gè)容器實(shí)現(xiàn),可以歸為兩種不同的類型告组。bean工廠(由org.springframework. beans.factory.eanFactory接口定義)是最簡(jiǎn)單的容器煤伟,提供基本的DI支持。應(yīng)用上下文
(由org.springframework.context.ApplicationContext接口定義)基于BeanFactory構(gòu)建木缝,并提供應(yīng)用框架級(jí)別的服務(wù)便锨,例如從屬性文件解析文本信息以及發(fā)布應(yīng)用事件給感興趣的事件監(jiān)聽者。

雖然我們可以在bean工廠和應(yīng)用上下文之間任選一種我碟,但bean工廠對(duì)大多數(shù)應(yīng)用來說往往太低級(jí)了放案,因此,應(yīng)用上下文要比bean工廠更受歡迎矫俺。我們會(huì)把精力集中在應(yīng)用上下文的使用上吱殉,不再浪費(fèi)時(shí)間討論bean工廠。

bean的生命周期

在傳統(tǒng)的Java應(yīng)用中厘托,bean的生命周期很簡(jiǎn)單友雳。使用Java關(guān)鍵字new進(jìn)行bean實(shí)例化,然后該bean就可以使用了铅匹。一旦該bean不再被使用押赊,則由Java自動(dòng)進(jìn)行垃圾回收。相比之下包斑,Spring容器中的bean的生命周期就顯得相對(duì)復(fù)雜多了流礁。正確理解Spring bean的生命周期非常重要涕俗,因?yàn)槟慊蛟S要利用Spring提供的擴(kuò)展點(diǎn)來自定義bean的創(chuàng)建過程。下圖展示了bean裝載到Spring應(yīng)用上下文中的一個(gè)典型的生命周期過程崇棠。

Spring bean的生命周期

bean在Spring容器中從創(chuàng)建到銷毀經(jīng)歷了若干階段咽袜,每一階段都可以針對(duì)Spring如何管理bean進(jìn)行個(gè)性化定制。

正如你所見枕稀,在bean準(zhǔn)備就緒之前询刹,bean工廠執(zhí)行了若干啟動(dòng)步驟。
我們對(duì)圖1.5進(jìn)行詳細(xì)描述:
1.Spring對(duì)bean進(jìn)行實(shí)例化萎坷;
2.Spring將值和bean的引用注入到bean對(duì)應(yīng)的屬性中凹联;
3.如果bean實(shí)現(xiàn)了BeanNameAware接口,Spring將bean的ID傳遞給setBean-Name()方法哆档;
4.如果bean實(shí)現(xiàn)了BeanFactoryAware接口蔽挠,Spring將調(diào)用setBeanFactory()方法,將BeanFactory容器實(shí)例傳入瓜浸;
5.如果bean實(shí)現(xiàn)了ApplicationContextAware接口澳淑,Spring將調(diào)用setApplicationContext()方法,將bean所在的應(yīng)用上下文的引用傳入進(jìn)來插佛;
6.如果bean實(shí)現(xiàn)了BeanPostProcessor接口杠巡,Spring將調(diào)用它們的post-ProcessBeforeInitialization()方法;
7.如果bean實(shí)現(xiàn)了InitializingBean接口雇寇,Spring將調(diào)用它們的after-PropertiesSet()方法氢拥。類似地,如果bean使用initmethod聲明了初始化方法锨侯,該方法也會(huì)被調(diào)用嫩海;
8.如果bean實(shí)現(xiàn)了BeanPostProcessor接口,Spring將調(diào)用它們的post-ProcessAfterInitialization()方法囚痴;
9.此時(shí)叁怪,bean已經(jīng)準(zhǔn)備就緒,可以被應(yīng)用程序使用了深滚,它們將一直駐留在應(yīng)用上下文中骂束,直到該應(yīng)用上下文被銷毀;
10.如果bean實(shí)現(xiàn)了DisposableBean接口成箫,Spring將調(diào)用它的destroy()接口方法展箱。同樣,如果bean使用destroy-method聲明了銷毀方法蹬昌,該方法也會(huì)被調(diào)用混驰。

現(xiàn)在你已經(jīng)了解了如何創(chuàng)建和加載一個(gè)Spring容器。但是一個(gè)空的容器并沒有太大的價(jià)值,在你把東西放進(jìn)去之前栖榨,它里面什么都沒有昆汹。為了從Spring的DI中受益,我們必須將應(yīng)用對(duì)象裝配進(jìn)Spring容器中婴栽。

Spring模塊

Spring模塊組成

小結(jié)

現(xiàn)在满粗,你應(yīng)該對(duì)Spring的功能特性有了一個(gè)清晰的認(rèn)識(shí)。Spring致力于簡(jiǎn)化企業(yè)級(jí)Java開發(fā)愚争,促進(jìn)代碼的松散耦合映皆。成功的關(guān)鍵在于依賴注入和AOP。

在本章轰枝,我們先體驗(yàn)了Spring的DI捅彻。DI是組裝應(yīng)用對(duì)象的一種方式,借助這種方式對(duì)象無需知道依賴來自何處或者依賴的實(shí)現(xiàn)方式鞍陨。不同于自己獲取依賴對(duì)象步淹,對(duì)象會(huì)在運(yùn)行期賦予它們所依賴的對(duì)象。依賴對(duì)象通常會(huì)通過接口調(diào)用所注入的對(duì)象诚撵,這樣的話就能確保低耦合缭裆。

除了DI,我們還簡(jiǎn)單介紹了Spring對(duì)AOP的支持寿烟。AOP可以幫助應(yīng)用將散落在各處的邏輯匯集于一處——切面澈驼。當(dāng)Spring裝配bean的時(shí)候,這些切面能夠在運(yùn)行期編織起來韧衣,這樣就能非常有效地賦予bean新的行為。

依賴注入和AOP是Spring框架最核心的部分购桑,因此只有理解了如何應(yīng)用Spring最關(guān)鍵的功能畅铭,你才有能力使用Spring框架的其他功能。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勃蜘,一起剝皮案震驚了整個(gè)濱河市硕噩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缭贡,老刑警劉巖炉擅,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異阳惹,居然都是意外死亡谍失,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門框咙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓶堕,“玉大人胶哲,你說我怎么就攤上這事拥刻∧ㄖ瘢” “怎么了线罕?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)窃判。 經(jīng)常有香客問我钞楼,道長(zhǎng),這世上最難降的妖魔是什么袄琳? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任询件,我火速辦了婚禮,結(jié)果婚禮上跨蟹,老公的妹妹穿的比我還像新娘雳殊。我一直安慰自己,他們只是感情好窗轩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布夯秃。 她就那樣靜靜地躺著,像睡著了一般痢艺。 火紅的嫁衣襯著肌膚如雪仓洼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天堤舒,我揣著相機(jī)與錄音色建,去河邊找鬼。 笑死舌缤,一個(gè)胖子當(dāng)著我的面吹牛箕戳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播国撵,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼陵吸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了介牙?” 一聲冷哼從身側(cè)響起壮虫,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎环础,沒想到半個(gè)月后囚似,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡线得,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年饶唤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贯钩。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡搬素,死狀恐怖呵晨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情熬尺,我是刑警寧澤摸屠,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站粱哼,受9級(jí)特大地震影響季二,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜揭措,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一胯舷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绊含,春花似錦桑嘶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至充甚,卻和暖如春以政,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伴找。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工盈蛮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人技矮。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓抖誉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親衰倦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子袒炉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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

  • 依賴注入 按照傳統(tǒng)的做法,每個(gè)對(duì)象負(fù)責(zé)管理與自己相互協(xié)作的對(duì)象的引用耿币,這將會(huì)導(dǎo)致高度耦合和難以測(cè)試的代碼梳杏。例如: ...
    謝隨安閱讀 537評(píng)論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理韧拒,服務(wù)發(fā)現(xiàn)淹接,斷路器,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 第一章 Spring之旅 [TOC] 前言 在誕生之初叛溢,創(chuàng)建spring的主要目的就是用來替代更加基重量級(jí)的企業(yè)...
    施瓦閱讀 477評(píng)論 2 1
  • 簡(jiǎn)潔的Spring 為了降低Java開發(fā)的復(fù)雜性塑悼,Spring采取了以下4種關(guān)鍵策略: 基于POJO的輕量級(jí)和最小...
    hoxis閱讀 4,293評(píng)論 5 22
  • 第一次用Axure RP8寫產(chǎn)品需求文檔,筆者為產(chǎn)品小白楷掉,希望通過這篇文章和大家分享以及學(xué)習(xí)交流厢蒜。 以下我的Axu...
    PM_allen閱讀 3,570評(píng)論 8 36