Spring AOP源碼流程解析

? ? Spring之所以成為java工程師界的“南天一柱谤碳,萬世楷牟男梗”悠鞍,除了有幫我們解決對象管理的IOC(可見我上一篇文章)染簇,還有對面向?qū)ο缶幊痰挠辛ρa充的AOP(Aspect Oriented Programming)面向切面編程参滴。還是那個古老的話題,專業(yè)術(shù)語可以幫我簡化交流復(fù)雜度锻弓,卻對概念進行了封裝砾赔,讓其變得晦澀難懂。所以我們需要搞清楚的第一點就是何為“面向切面”弥咪?為什么一定需要“面向切面”过蹂?不需要行不行?

? ? 這里補充一句聚至,昨天有朋友跟我反饋了下酷勺,希望我可以多聊些Spring里的設(shè)計模式。首先我非常感謝有這些能夠認真看完我這個菜雞博客并且經(jīng)過思考還提出寶貴意見的朋友扳躬,也正是你們我才能樂此不疲的繼續(xù)寫下去^_^脆诉!但我個人的觀點是我們拿到一個問題,正常邏輯是先去分析問題贷币,然后解決問題击胜,至于解決方案,那是仁者見仁智者見智的事兒役纹。就像面向切面也不是非要動態(tài)代理不可偶摔,用內(nèi)部類一樣可以做到。當(dāng)然了促脉,Spring AOP中確實相比于IOC要復(fù)雜的多辰斋,所以自然有相當(dāng)?shù)牟诲e的設(shè)計模式模式,后面咱們再細聊這個問題瘸味。首先宫仗,我們還是先把目光放到我們最開始的問題上,不忘初心嘛~~

? ? 軟件工程旁仿,不僅僅是實現(xiàn)一個功能就完事了藕夫,隨著時間的推移,版本的迭代枯冈,會產(chǎn)生不計其數(shù)的需求變更毅贮。有一句笑話叫作“寫時一時爽,重構(gòu)火葬場”講的就是寫代碼的人沒有考慮過未來的變更場景尘奏,導(dǎo)致修改時候的工作量如同再造滩褥,那你加班加到猝死不能也怪資本主義丑陋的面目吧,哈哈哈罪既。所以我們希望的就是能否有這樣的一個功能铸题,當(dāng)我們要往1000個類上面加一個功能時候,不需要修改這1000個類琢感,而是有一個名為切面的類丢间,里面寫上我們需要添加的功能,然后分別切開那1000個類驹针,悄悄的幫我們把功能填進去烘挫。也正是這么個奇思妙想,造就了現(xiàn)如今的偉大的AOP模塊柬甥!

? ? 在我剛開始學(xué)習(xí)Spring AOP的時候也去網(wǎng)上找了很多博客饮六,其實他們大致都是千篇一律的講JDK動態(tài)代理和Cglib,然后大刀闊斧的在講代理模式苛蒲,適配器模式這類設(shè)計模式卤橄。我不是覺得他們講的不好講的不對。只是他們都在很細化的講“廬山”的某一花某一草某一木臂外,我看完之后還是不是很清楚這個“廬山”真面目窟扑。我不知道你們有沒想過這個問題。那些博客說了那么多代理對象原理漏健,請問這個代理對象什么時候?qū)⑽疫@個正常的對象給貍貓換太子成代理對象嚎货?所以,為了給我的好奇心買單蔫浆,我開始著手于AOP的源碼殖属。

? ? Spring的IOC是基石,所以即便是AOP也會將對象托管給IOC容器瓦盛∠聪裕回到最開始的需求,我既然把對象給你Spring管理谭溉,自然存在向你索取的需求墙懂,所以我還是以getBean為線索展開。開始之前扮念,我先解釋一下幾個概念损搬,因為Spring的類的含義往往從它的名字中暴露出來,可以減少閱讀源碼負擔(dān)柜与。

1.? Advice:通知巧勤。雖然我至今還不清楚老外為什么取名字,所以不管它語言含義弄匕。Advice是AOP聯(lián)盟定義的接口颅悉,代表切面行為。Spring自身提供了三種切面切入的方式迁匠,落實到Spring源碼中的類是MethodBeforeAdviceInterceptor剩瓶,AfterReturningAdviceInterceptor驹溃,ThrowsAdviceInterceptor。也就是我們熟悉在目標方法之前之前執(zhí)行切面邏輯延曙,目標方法返回之前執(zhí)行切面邏輯豌鹤,拋出異常的時候執(zhí)行切面邏輯

2.? PointCut:切點。這個比較容易理解枝缔,就是要被代理的方法布疙,也就是我們所說的目標方法

3. Advisor:通知器。封裝Advice愿卸,PointCut灵临。因為我們通常在配置文件中聲明一個切面配置的時候,Advice和Pointcut都是成對出現(xiàn)的趴荸,不是嗎儒溉?

定位需要代理的bean


返回代理bean

????上述的匹配方法是采用的AspectJ的庫函數(shù),具體做法目前不是我們關(guān)心的重點发钝,其實也就是玩轉(zhuǎn)字符串睁搭,匹配 <property name ="expression" value ="execution(* main.Knight.say(..))">?中的Knight是不是和我這個bean(類型為main.Knight)一致,就像JSON工具包笼平,雖然我也不知道他的具體做法园骆,但我知道底層大致的做法足矣。

? ? 如此一來寓调,我們就清楚了AOP是如何做到“貍貓換太子”了锌唾。接下來就是眾多博客都有講解的JDK Proxy 和Cglib做法了。Spring源碼在決定生成代理對象的時候會去判斷下目標類有沒有實現(xiàn)接口夺英,如果實現(xiàn)了接口就生成Proxy代理對象晌涕,如果沒有實現(xiàn)接口就通過Cglib生成一個類去繼承目標類,復(fù)寫目標類中需要加入切面邏輯的方法痛悯,所以目標類方法不能聲明稱final類型的余黎。這就是二者的區(qū)別!這不是我最關(guān)心的地方载萌,其實若想知道他們二者的本質(zhì)區(qū)別惧财,只要寫一個小demo,然后用反編譯的工具就可以一探二者究竟扭仁,這里就不贅述了垮衷,下面我也只介紹Proxy。

? ? Spring中JDK 的Proxy類名曰JdkDynamicAopProxy乖坠,也就是我們耳熟能詳?shù)膭討B(tài)代理搀突。這個類主要實現(xiàn)了AopProxy,InvocationHandler接口

JdkDynamicAopProxy方法

? ? 所謂的代理模式就是熊泵,當(dāng)你對代理對象調(diào)用目標類的方法時候仰迁,JVM都會觸發(fā)上圖這個invoke方法甸昏,以改變方法調(diào)用的軌跡,實現(xiàn)切面邏輯的悄悄織入徐许,這是被API封裝掉的筒扒,如果想落實真相,可以去反編譯绊寻。我們先看看invoke里面都做了什么?


Proxy中的方法加強真相


methodInterceptor.invoke()真相

? ? 沒錯,methodInvocation.procceed()就是一個回調(diào)方法。


methodInvocation.procceed()

? ? 看到?jīng)]有爽锥,這個procceed就是通過反射的機制調(diào)用目標對象的方法空执。只不過他的調(diào)用需要交給攔截器來調(diào)用,也就是所謂的回調(diào)供汛。

? ? 如此一來Spring實現(xiàn)AOP的脈絡(luò)就很清楚了,真實的Spring AOP是非常非常復(fù)雜的。除非親自去看梯皿,不然很難在有限的篇幅講清楚,而且本人還是那句話县恕,解決方案是應(yīng)運著需求的东羹,技術(shù)總是后知后覺得,有印象的朋友可能會記得我在前面提到過Spring AOP有用到適配器這種設(shè)計模式忠烛,為什么我到現(xiàn)在都沒提及過属提,那是因為我給出都是Spring AOP代理過程中最理想最簡單的情況,自然不需要想盡辦法利用多態(tài)的性質(zhì)去簡化代碼美尸。

? ? 還記得我前面留下的問題冤议,為什么methodInterceptor就當(dāng)它是Advice了。因為我給出的切面邏輯是單一的师坎,真實的使用切面邏輯是三個恕酸,before,afterReturning胯陋,throws蕊温。所以Spring源碼在執(zhí)行目標方法之前是有一個攔截鏈的,里面有多個攔截器遏乔,這多個攔截器執(zhí)行完成之后才會執(zhí)行目標方法寿弱。

? ? 適配器是吧,直接上圖按灶!


DefaultAdvisorAdapterRegistry.getInterceptors(Advisor advisor)

????Spring源碼是想干啥呢症革?我解釋一下,我現(xiàn)在手上有一堆從配置文件獲得的Advice鸯旁,但我想獲得我想要的攔截器噪矛,因為攔截器才是真正改變目標方法的地方量蕊。但是有由于advice這個對象究竟是before,afterReturning還是throws不得而知艇挨,所以我們用適配器去適配它残炮,目的是為了生成對應(yīng)的不同的攔截器。adapters是一個List缩滨,里面分別裝有MethodBeforeAdviceAdapter势就,AfterReturningAdviceAdapter,ThrowsAdviceAdapter脉漏。我們的做法就是遍歷它們苞冯,然后去supportsAdvice()。下面我舉一個AfterReturningAdvice例子侧巨,其他兩個可類推舅锄。


AfterReturningAdviceAdapter.supportsAdvice(Advice advice)

? ? 這就是所謂的適配器設(shè)計模式。本質(zhì)還是面向?qū)ο蟮亩鄳B(tài)司忱,不同的玩法而已皇忿,而且instanceof不到萬不得以的地步不要使用,因為這樣會是代碼的擴展性變得不好坦仍。至于簡單工廠鳍烁,單例模式這種老掉牙的設(shè)計模式就不必也來Spring中湊數(shù)了

? ? 好了,Spring AOP也落下帷幕了繁扎。我雖然還沒工作老翘,但是實習(xí)也大半年了,我自己的感覺真實生產(chǎn)中Spring IOC比AOP使用的要多一些锻离,或者說AOP是衣架子铺峭,先人已經(jīng)做的挺好的,我們只需要改一改換一換衣架上的衣服罷了汽纠。而且Spring AOP的使用意識其實比Spring AOP的原理在生產(chǎn)中來的更實際一些卫键。

? ? 最后,分享一波阿里云的面試心得:我今年2月份的時候面試了下阿里云的實習(xí)生虱朵。其中有一個面試題就是針對我在上一家公司的業(yè)務(wù)莉炉,業(yè)務(wù)是這樣的:鏡像刪除,既要將數(shù)據(jù)庫中的鏡像信息刪除碴犬,還要將調(diào)用鏡像倉庫服務(wù)進程的API絮宁,實現(xiàn)鏡像描述信息和實際的鏡像文件都刪除。我的回答也比較耿直服协,因為確實是這么做的绍昂,我說我先將數(shù)據(jù)庫中的鏡像信息刪除,然后刪除鏡像文件,并且為了提升前端的響應(yīng)速度窘游,我采用異步的方式唠椭,創(chuàng)建子線程的方式去調(diào)鏡像倉庫的API。面試官問:那如果數(shù)據(jù)庫出現(xiàn)異常會怎么樣忍饰?我:數(shù)據(jù)會回滾贪嫂,這是Spring的事務(wù)管理機制。面試官:好艾蓝,那數(shù)據(jù)回滾了力崇,鏡像倉庫的鏡像沒了,你怎么辦赢织?我:亮靴。。敌厘。

? ? 結(jié)果可想而知,我掛了朽合。其實這是一個非常簡單的問題俱两,只怪當(dāng)初我對AOP的理解和數(shù)據(jù)庫事務(wù)的理解太過僵硬。首先我沒有抓住事務(wù)的本質(zhì)曹步,為什么只有操作數(shù)據(jù)庫才算是一個事務(wù)宪彩?事務(wù)的本質(zhì)就是將一堆行為作為一個整體來看,要么一起成功要么一起失敗讲婚。就像數(shù)據(jù)庫刪除鏡像信息和刪除鏡像文件尿孔,這兩樣事情就是要么一起成功要么一起失敗,所以應(yīng)該將二者視為一個事務(wù)筹麸。

? ? 因此解決方案很簡單活合,只要在這個業(yè)務(wù)函數(shù)的整體上加一個@Transaction即可,@Transaction就是一個AOP物赶,在業(yè)務(wù)函數(shù)開始之前transaction.start()白指。然后try catch住整個方法,無論數(shù)據(jù)庫還是調(diào)用鏡像倉庫API只要拋出異常執(zhí)行transaction,rollback()酵紫。方法返回之前調(diào)用transaction.commit()告嘲。是不是就對應(yīng)了before,afterReturning奖地,throws啊橄唬。

? ? Spring的實現(xiàn)是復(fù)雜的,如何講清楚他参歹,從構(gòu)思到攥寫都是相當(dāng)耗時耗力的仰楚。我也總算告一段落了,希望這兩篇博客可以給予JAVA開發(fā)的同學(xué)一點幫助。

????后續(xù)的話我還會寫一些Mysql缸血,Hadoop蜜氨,Kubernetes博客,希望技術(shù)不再是逼格的代表捎泻,而是藝術(shù)的化身飒炎!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市笆豁,隨后出現(xiàn)的幾起案子郎汪,更是在濱河造成了極大的恐慌,老刑警劉巖闯狱,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件煞赢,死亡現(xiàn)場離奇詭異,居然都是意外死亡哄孤,警方通過查閱死者的電腦和手機照筑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘦陈,“玉大人凝危,你說我怎么就攤上這事〕渴牛” “怎么了蛾默?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捉貌。 經(jīng)常有香客問我支鸡,道長,這世上最難降的妖魔是什么趁窃? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任牧挣,我火速辦了婚禮,結(jié)果婚禮上醒陆,老公的妹妹穿的比我還像新娘浸踩。我一直安慰自己,他們只是感情好统求,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布检碗。 她就那樣靜靜地躺著,像睡著了一般码邻。 火紅的嫁衣襯著肌膚如雪折剃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天像屋,我揣著相機與錄音怕犁,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛奏甫,可吹牛的內(nèi)容都是我干的戈轿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼阵子,長吁一口氣:“原來是場噩夢啊……” “哼思杯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起挠进,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤色乾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后领突,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體暖璧,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年君旦,在試婚紗的時候發(fā)現(xiàn)自己被綠了澎办。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡金砍,死狀恐怖局蚀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捞魁,我是刑警寧澤至会,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布离咐,位于F島的核電站谱俭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏宵蛀。R本人自食惡果不足惜昆著,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望术陶。 院中可真熱鬧凑懂,春花似錦、人聲如沸梧宫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽塘匣。三九已至脓豪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間忌卤,已是汗流浹背扫夜。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人笤闯。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓堕阔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親颗味。 傳聞我的和親對象是個殘疾皇子超陆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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

  • 說明:本文主要內(nèi)容來自慕課網(wǎng)。配合視頻食用口味更佳脱衙。主要是順著已經(jīng)學(xué)習(xí)的視頻順序總結(jié)一遍侥猬,以深化理解和方便日后復(fù)習(xí)...
    stoneyang94閱讀 849評論 3 5
  • 概述 Spring是什么? Spring是一個開源框架捐韩,為了解決企業(yè)應(yīng)用開發(fā)的復(fù)雜性而創(chuàng)建的退唠,但是現(xiàn)在已經(jīng)不止于企...
    瑯筑閱讀 1,153評論 2 8
  • 親愛的時光: 您好滩愁。 我感謝你――讓我變的如此堅強。 兒時的我畏懼困難辫封,畏懼挫折硝枉,是你,默...
    醉夢似水流年轉(zhuǎn)閱讀 138評論 0 0
  • 淚光 嘿 你好 眼角的淚光 我是飛舞的蝶 是夢中的影 是你的我 嘿眼角的淚光 你在躲避我嗎倦微? 你也覺得我討厭妻味? 你...
    她笑了閱讀 284評論 0 1
  • 合作 “警官,我知道你在苦惱什么欣福,我大概责球,可以幫助你。我可真是個合作的好市民啊拓劝〕猓”陸啟文的背后,是從病房緊隨他出來...
    花京體驗閱讀 279評論 1 1