Spring的IOC與AOP特性

Spring的IOC特性


一. 什么是控制反轉(zhuǎn)


圖1. 控制反轉(zhuǎn)

見圖1,軟件中的對(duì)象就如同圖中的齒輪,協(xié)同工作,互相耦合,若是一個(gè)零件不能正常工作,則會(huì)導(dǎo)致整個(gè)系統(tǒng)的奔潰,這就是強(qiáng)耦合系統(tǒng)。為了解決對(duì)象間耦合度過高的問題,軟件專家Michael Mattson提出了IoC理論。

控制反轉(zhuǎn)(Inversion of Control)是一種面向?qū)ο缶幊讨械囊环N設(shè)計(jì)原則,用來(lái)解決計(jì)算機(jī)代碼之間的耦合度。其基本思想是:借助于"第三方"實(shí)現(xiàn)具有依賴關(guān)系的對(duì)象之間的耦合。

圖2. IoC

見圖2,由于引進(jìn)了IoC容器,使得A、B、C、D這四個(gè)對(duì)象沒有了耦合關(guān)系,對(duì)象的控制權(quán)全部由IoC容器負(fù)責(zé)。

我們?cè)俅蝸?lái)對(duì)比一下:

  1. 軟件系統(tǒng)在沒有引入IoC容器之前,如圖1,對(duì)象A依賴與對(duì)象B,那么對(duì)象A在初始化或者運(yùn)行到某一點(diǎn)的時(shí)候,自己必須主動(dòng)去創(chuàng)建對(duì)象B或者使用已經(jīng)創(chuàng)建的對(duì)象B。無(wú)論是創(chuàng)建還是使用對(duì)象B,控制權(quán)都在自己手上。
  2. 軟件系統(tǒng)在引入IoC容器之后,就完全不同了。如圖2,由于IoC容器的加入,對(duì)象A與對(duì)象B之間失去了直接聯(lián)系,所以,當(dāng)對(duì)象A運(yùn)行到需要B的對(duì)象,IoC容器會(huì)主動(dòng)創(chuàng)建一個(gè)對(duì)象B注入到對(duì)象A需要的地方。

通過對(duì)比,可以看出對(duì)象A依賴對(duì)象B的過程,由主動(dòng)行為變成了被動(dòng)行為,控制權(quán)顛倒了過來(lái),這就是"控制反轉(zhuǎn)"的由來(lái)。

二. 什么是依賴注入


當(dāng)A對(duì)象需要調(diào)用B對(duì)象方法時(shí),這種情況在Spring中稱為依賴,即A對(duì)象依賴B對(duì)象,Spring把互相調(diào)用的關(guān)系稱為依賴關(guān)系。

在傳統(tǒng)模式下當(dāng)需要調(diào)用其他對(duì)象的方法時(shí),一般有以下兩種方式:

  • 原始做法:調(diào)用者主動(dòng)創(chuàng)建被依賴對(duì)象,然后再調(diào)用被依賴對(duì)象的方法。
  • 簡(jiǎn)單工廠模式:調(diào)用者先找到被依賴對(duì)象的工廠,然后主動(dòng)通過工廠去獲取被依賴對(duì)象,最后再調(diào)用被依賴對(duì)象的方法。

對(duì)于第一種方式,由于調(diào)用者需要通過形如"new 被依賴對(duì)象構(gòu)造器();"的代碼來(lái)創(chuàng)建對(duì)象,這種方式會(huì)導(dǎo)致調(diào)用者與被依賴對(duì)象實(shí)現(xiàn)類的硬編碼耦合,不利于項(xiàng)目升級(jí)維護(hù)。

對(duì)于第二種方式,要把握一下三點(diǎn):

  • 調(diào)用者面向被依賴對(duì)象的接口編程
  • 將被依賴對(duì)象的創(chuàng)建交給工廠完成
  • 調(diào)用者通過工廠來(lái)獲得被依賴組件

這樣,調(diào)用者只需與被依賴對(duì)象的接口耦合,這樣就避免了類層次的硬編碼耦合。缺點(diǎn)是,調(diào)用組件需要主動(dòng)通過工廠去獲取被依賴對(duì)象,這就會(huì)帶來(lái)調(diào)用組件與被依賴對(duì)象的耦合。

當(dāng)使用Spring容器后,程序無(wú)須使用new調(diào)用構(gòu)造器去創(chuàng)建對(duì)象,所有的Java對(duì)象都可交給Spring容器去創(chuàng)建;當(dāng)調(diào)用者需要被依賴對(duì)象的方法時(shí),調(diào)用者無(wú)須主動(dòng)獲取被依賴對(duì)象,只需要等待Spring容器注入即可。

三. 控制反轉(zhuǎn)與依賴注入的關(guān)系


  • 控制反轉(zhuǎn)是一種思想
  • 依賴注入是一種設(shè)計(jì)模式

IoC框架使用依賴注入作為實(shí)現(xiàn)控制反轉(zhuǎn)的方式,但是控制反轉(zhuǎn)還有其他的實(shí)現(xiàn)方式,例如說ServiceLocator,所以不能將控制反轉(zhuǎn)和依賴注入等同。

參考資料


Spring的AOP特性


以下內(nèi)容來(lái)自于博客Spring AOP 實(shí)現(xiàn)原理與 CGLIB 應(yīng)用

AOP(Aspect Orient Programming),作為面向?qū)ο缶幊痰囊环N補(bǔ)充,廣泛應(yīng)用于處理一些具有橫切性質(zhì)的系統(tǒng)級(jí)服務(wù),如事務(wù)管理、安全檢查、緩存、對(duì)象池管理等。AOP實(shí)現(xiàn)的關(guān)鍵就在于AOP框架自動(dòng)創(chuàng)建的AOP代理,AOP代理則可分為靜態(tài)代理和動(dòng)態(tài)代理兩大類,其中靜態(tài)代理是指AOP框架提供的命令進(jìn)行編譯,從而在編譯階段就可生成AOP代理類,因此也被稱為編譯時(shí)增強(qiáng);而動(dòng)態(tài)代理則是在運(yùn)行時(shí)借助于JDK動(dòng)態(tài)代理、CGLIB等在內(nèi)存中“臨時(shí)”生成AOP動(dòng)態(tài)代理類,因此也被稱為運(yùn)行時(shí)增強(qiáng)。

一. AOP的存在價(jià)值


在傳統(tǒng)的OOP編程里以對(duì)象為核心,整個(gè)軟件系統(tǒng)由一系列相互依賴的對(duì)象組成,而這些對(duì)象將被抽象成一個(gè)個(gè)類,并允許使用類繼承來(lái)管理類與類之間一般到特殊的關(guān)系。隨著軟件規(guī)模的增大,應(yīng)用的逐漸升級(jí),慢慢出現(xiàn)了一些OOP很難解決的問題。

我們可以通過分析、抽象出一系列具有一定屬性與行為的對(duì)象,并通過這些對(duì)象的協(xié)作來(lái)形成一個(gè)完整的軟件功能。由于對(duì)象可以繼承,因此我們可以把具有相同功能或相同特性的屬性抽象到一個(gè)層次分明的類結(jié)構(gòu)體系中。隨著軟件規(guī)范的不斷擴(kuò)大,專業(yè)化分工越來(lái)越系列,以及OOP應(yīng)用實(shí)踐的不斷增多,隨之也暴露出了一些OOP無(wú)法很好解決的問題。

現(xiàn)在假設(shè)系統(tǒng)中有3段完全相似的代碼,這些代碼通常會(huì)采用“復(fù)制”、“粘貼”方式來(lái)完成,通過這種“復(fù)制”、“粘貼”方式開發(fā)出來(lái)的軟件如圖1所示。


圖1. 多個(gè)地方包含相同代碼的軟件

看到如圖1所示的示意圖,可以看到了這種設(shè)計(jì)的不足之處。當(dāng)有一天,圖1中的深色代碼段需要修改,那是不是要打開3個(gè)地方的代碼進(jìn)行修改?如果不是3個(gè)地方包含這段代碼,而是100個(gè)地方,甚至是1000個(gè)地方包含這段代碼段,那會(huì)是什么后果?

為了解決這個(gè)問題,我們通常會(huì)采用將如圖1所示的深色代碼部分定義成一個(gè)方法,然后在3個(gè)代碼段中分別調(diào)用該方法即可。在這種方式下,軟件系統(tǒng)的結(jié)構(gòu)如圖2所示。


圖2. 通過方法調(diào)用實(shí)現(xiàn)系統(tǒng)功能

對(duì)于如圖2所示的軟件系統(tǒng),如果需要修改深色部分的代碼,只要修改一個(gè)地方即可,不管整個(gè)系統(tǒng)中有多少方法調(diào)用了該方法,程序無(wú)須修改這些地方,只需要修改被調(diào)用的方法即可——通過這種方式,大大降低了軟件后期維護(hù)的復(fù)雜度。

對(duì)于如圖2所示的方法1、方法2、方法3依然需要顯式調(diào)用深色方法,這樣做能夠解決大部分應(yīng)用場(chǎng)景。但對(duì)于一些更特殊的情況:應(yīng)用需要方法1、方法2、方法3徹底與深色方法分離——方法1、方法2、方法3無(wú)須直接調(diào)用深色方法,該如何解決?

因?yàn)檐浖到y(tǒng)需求變更是非常頻繁的事情,系統(tǒng)前期設(shè)計(jì)方法1、方法2、方法3時(shí)只實(shí)現(xiàn)了核心業(yè)務(wù)功能,過了一段時(shí)間,我們需要為方法1、方法2、方法3都增加事務(wù)控制;又過了一段時(shí)間,客戶提出方法1、方法2、方法3需要進(jìn)行用戶合法性驗(yàn)證。只有合法的用戶才能執(zhí)行這些方法。因此,我們希望有一種特殊的方法:我們只要定義該方法,無(wú)須在方法1、方法2、方法3中顯式調(diào)用它,系統(tǒng)會(huì)“自動(dòng)”執(zhí)行該特殊方法。

實(shí)現(xiàn)上述需求的技術(shù)就是AOP。AOP專門用于處理系統(tǒng)中分布于各個(gè)模塊(不同方法)中交叉關(guān)注點(diǎn)的問題,在JavaEE應(yīng)用中,常常通過AOP來(lái)處理一些具有橫切性質(zhì)的系統(tǒng)級(jí)服務(wù),如事務(wù)管理、安全檢查、緩存、對(duì)象池管理等,AOP已經(jīng)成為一種非常常用的解決方案。

二. Spring AOP原理剖析

Spring AOP框架對(duì)AOP代理類的處理原則是:如果目標(biāo)對(duì)象的實(shí)現(xiàn)類實(shí)現(xiàn)了接口,Spring AOP將會(huì)采用JDK動(dòng)態(tài)代理來(lái)生成AOP代理類;如果目標(biāo)對(duì)象的實(shí)現(xiàn)類沒有實(shí)現(xiàn)接口,Spring AOP將會(huì)采用CGLIB來(lái)生成AOP代理類——不過這個(gè)選擇過程對(duì)開發(fā)者完全透明、開發(fā)者無(wú)須關(guān)心。

AOP代理其實(shí)是由AOP框架動(dòng)態(tài)生成的一個(gè)對(duì)象,該對(duì)象可作為目標(biāo)對(duì)象使用。AOP代理包含了目標(biāo)對(duì)象的全部方法,但AOP代理中的方法與目標(biāo)對(duì)象的方法存在差異:AOP方法在特定切入點(diǎn)添加了增強(qiáng)處理,并回調(diào)了目標(biāo)對(duì)象的方法。

AOP代理所包含的方法與目標(biāo)對(duì)象的方法示意圖如圖3所示。


圖3. AOP代理的方法與目標(biāo)對(duì)象的方法

Spring的AOP代理有Spring的IoC容器負(fù)責(zé)生成、管理,其依賴關(guān)系也有IoC容器負(fù)責(zé)管理。因此,AOP代理可以直接使用容器中的其他Bean實(shí)例作為目標(biāo),這種關(guān)系可由IoC容器的依賴注入提供。

縱觀AOP編程,其中需要程序員參與的只有3個(gè)部分:

  • 定義普通業(yè)務(wù)組件
  • 定義切入點(diǎn),一個(gè)切入點(diǎn)可能橫切多個(gè)業(yè)務(wù)組件
  • 定義增強(qiáng)處理,增強(qiáng)處理就是在AOP框架為普通業(yè)務(wù)組件織入的處理動(dòng)作

上面3個(gè)部分的第一個(gè)部分是最平常不過的事情,無(wú)須額外說明。那么進(jìn)行AOP編程的關(guān)鍵就是定義切入點(diǎn)和定義增強(qiáng)處理。一但定義了合適的切入點(diǎn)和增強(qiáng)處理,AOP框架將會(huì)自動(dòng)生成AOP代理,而AOP代理的方法大致有如下公式:

代理對(duì)象的方法 = 增強(qiáng)處理 + 被代理對(duì)象的方法

Spring AOP的實(shí)現(xiàn)原理:AOP框架負(fù)責(zé)動(dòng)態(tài)生成AOP代理類,這個(gè)代理類的方法則由Advice和回調(diào)方法對(duì)象的方法所組成。

對(duì)于前面提到的圖2所示的軟件調(diào)用結(jié)構(gòu):當(dāng)方法1、方法2、方法3......都需要去調(diào)用某個(gè)具有“橫切”性質(zhì)的方法時(shí),傳統(tǒng)的做法是程序員去手動(dòng)修改方法1、方法2、方法3......通過代碼來(lái)調(diào)用這個(gè)具有“橫切”性質(zhì)的方法,但這種做法的可擴(kuò)展性不好,因?yàn)槊看味家薷拇a。

于是AOP框架出現(xiàn),AOP框架則可以“動(dòng)態(tài)的”生成一個(gè)新的代理類,而這個(gè)代理類所包含的方法1、方法2、方法3的代碼,程序員只要定義切入點(diǎn)即可——AOP框架所生成的AOP代理類中包含了新的方法1、方法2、方法3,而AOP框架會(huì)根據(jù)切入點(diǎn)來(lái)決定是否要在方法1、方法2、方法3中回調(diào)具有“橫切”性質(zhì)的方法。

簡(jiǎn)而言之:AOP原理的奧妙就在于動(dòng)態(tài)地生成了代理類,這個(gè)代理類實(shí)現(xiàn)了圖2的調(diào)用——這種調(diào)用無(wú)須程序員修改代碼。

參考資料


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

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