Spring AOP原理分析

AOP是Spring Core中幾大重要能力之一职恳,我們可以使用AOP實(shí)現(xiàn)很多功能,比如我們常用的日志處理與Spring中的聲明式事務(wù)蛹屿。

AOP的幾個(gè)重要概念

Aspect:切面屁奏,在Spring中意為所有通知方法所在的類(lèi)

Join point:連接點(diǎn),程序執(zhí)行中的一點(diǎn)错负,在Spring中只表示方法執(zhí)行(Spring只支持方法級(jí)別的攔截)

Advice:通知坟瓢,在特定連接點(diǎn)上采取的操作,Spring將通知抽象為攔截器犹撒,并圍繞連接點(diǎn)維護(hù)攔截器鏈折联。共有5種類(lèi)型,before(切點(diǎn)之前執(zhí)行)识颊,around(環(huán)繞執(zhí)行诚镰,即切點(diǎn)前后執(zhí)行),After returning(切點(diǎn)正常執(zhí)行完返回后執(zhí)行)祥款,After throwing(切點(diǎn)拋出異常后執(zhí)行)清笨,after(切點(diǎn)之后執(zhí)行,不管是異沉ぃ或正常結(jié)束)函筋,AOP攔截器鏈則為以上五種通知組成。我們可以在通知方法中獲得我們需要的參數(shù)(返回值奠伪,異常信息跌帐,代理對(duì)象等)

Pointcut:切點(diǎn),與通知一起出現(xiàn)绊率,使用專(zhuān)門(mén)的切點(diǎn)表達(dá)式?jīng)Q定在何處執(zhí)行通知方法谨敛。

Introduction:引入,為類(lèi)添加新的方法或字段滤否。

Target object:被代理的對(duì)象

AOP proxy:AOP代理對(duì)象脸狸,由JDK動(dòng)態(tài)代理或CGLIB代理生成

Weaving:織入,將通知等織入代理類(lèi)藐俺。Spring AOP是動(dòng)態(tài)織入(運(yùn)行時(shí)織入)炊甲,AspectJ則是靜態(tài)織入(編譯時(shí)織入)

幾個(gè)注意點(diǎn)

關(guān)于Spring AOP的具體使用這里不做介紹,具體見(jiàn)文檔欲芹,這里說(shuō)幾個(gè)在使用代理時(shí)需要注意的地方卿啡。

由于Spring AOP框架基于代理的特性,目標(biāo)對(duì)象內(nèi)的調(diào)用根據(jù)定義不會(huì)被攔截菱父。自調(diào)用即類(lèi)似this.bar()或this.foo()這樣的調(diào)用颈娜,即使在bar方法上有通知方法通知也不會(huì)執(zhí)行。對(duì)于JDK代理浙宜,只能攔截代理上的公共接口方法調(diào)用官辽。使用CGLIB,可以攔截代理上的公共和受保護(hù)方法調(diào)用(Cglib基于子父類(lèi)實(shí)現(xiàn)代理粟瞬,而私有方法不會(huì)被子類(lèi)繼承)同仆。當(dāng)多個(gè)通知都想在同一個(gè)連接點(diǎn)上運(yùn)行時(shí),他們將按照優(yōu)先級(jí)順序執(zhí)行裙品,優(yōu)先級(jí)順序可以使用Order接口來(lái)定義乓梨。

總結(jié)一句:自調(diào)用通知方法不執(zhí)行,私有方法通知不執(zhí)行清酥。

原理

接下來(lái)從源碼角度分析下Spring AOP的實(shí)現(xiàn)原理扶镀。

在Spring中我們使用@EnableAspectJautoProxy開(kāi)啟AOP功能,我們以此為入口焰轻。(其他的Enable注解分析原理都是一樣的臭觉,比如EnableAsync等)。

@EnableAspectJautoProxy

它使用@Import注解導(dǎo)入了AspectJAutoProxyRegistrar類(lèi)辱志,該類(lèi)實(shí)現(xiàn)了ImportBeanDefinitionRegistrar接口蝠筑,用于向Spring中注冊(cè)類(lèi)。

AspectJAutoProxyRegistrar

在registerBeanDefinitions方法的第一行注冊(cè)了AOP需要的相關(guān)bean揩懒,方法中的下面部分是取EnableAspectJAutoProxy注解的信息什乙,根據(jù)參數(shù)值做相應(yīng)的處理,這里主要關(guān)注方法的首行代碼已球,進(jìn)入registerAspectJAnnotationAutoProxyCreatorIfNecessary方法臣镣。

發(fā)現(xiàn)最終注冊(cè)了AnnotationAwareAspectJAutoProxyCreator辅愿。該類(lèi)是實(shí)現(xiàn)AOP的基礎(chǔ),我們對(duì)該類(lèi)進(jìn)行分析忆某,首先來(lái)看繼承結(jié)構(gòu)

BeanFactoryAware接口主要用于設(shè)置BeanFactory点待,這里我們主要關(guān)注InstantiationAwareBeanPostProcessor與BeanPostProcessor接口,實(shí)現(xiàn)這兩個(gè)接口意味著AnnotationAwareAspectJAutoProxyCreator是一個(gè)Spring的后置處理器弃舒,后置處理器會(huì)在bean的創(chuàng)建過(guò)程中起作用癞埠,關(guān)于后置處理器不熟悉的同學(xué)可以去看這篇文章Spring之IOC容器初始化

InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor有一個(gè)before與after接口聋呢,由接口名可知兩個(gè)方法分別在bean實(shí)例化前后調(diào)用苗踪,關(guān)于Spring中bean的實(shí)例化過(guò)程不清楚的可以看Spring Bean的實(shí)例化分析。我們?cè)谧宇?lèi)中找到他們的實(shí)現(xiàn)(after方法由于沒(méi)有特別的處理這里就省略了)

before的實(shí)現(xiàn)

首先從緩存中獲取削锰,然后調(diào)用this.isInfrastructureClass(beanClass)判斷創(chuàng)建的類(lèi)是否為Advice通铲、Pointcut等相關(guān)類(lèi),若是則放入adviseBean集合并返回null喂窟,正常的bean經(jīng)過(guò)該方法會(huì)返回null测暗,這里主要是用來(lái)處理我們的切面類(lèi)。

isInfrastructureClass

bean創(chuàng)建完成后接下來(lái)就是另一個(gè)接口BeanPostprocess(實(shí)例化磨澡,調(diào)用構(gòu)造函數(shù))開(kāi)始起作用了碗啄。

BeanPostprocess

他會(huì)在InstantiationAwareBeanPostProcessor(初始化,即BeanDefination的初始化)接口方法執(zhí)行完之后調(diào)用稳摄,查看其實(shí)現(xiàn)(before方法由于沒(méi)有特別的處理這里就省略了)

最終會(huì)調(diào)用wrapIfNecessary方法判斷該bean是否需要增強(qiáng)稚字。進(jìn)入方法

正常bean的創(chuàng)建會(huì)進(jìn)入到isInfrastructureClass這個(gè)分支,isInfrastructureClass這個(gè)方法就是之前分析的判斷是否是Aspect等注解的類(lèi)厦酬,如果不是則調(diào)用getAdvicesAndAdvisorsForBean方法獲取到符合該bean的通知方法(即相應(yīng)的Advisor)胆描。

最終調(diào)用createProxy創(chuàng)建代理對(duì)象。

createProxy
接上圖右側(cè)

最終進(jìn)入代理工廠創(chuàng)建代理對(duì)象的方法仗阅,根據(jù)是否實(shí)現(xiàn)接口自動(dòng)選擇創(chuàng)建JDK動(dòng)態(tài)代理(基于接口)或者是Cglib代理(基于子父類(lèi))昌讲。到這里切面以及要被代理的類(lèi)就都創(chuàng)建完成了,接下來(lái)就是如何運(yùn)行通知方法了减噪。

執(zhí)行流程

我們這里假設(shè)上一步創(chuàng)建的對(duì)象為Cglib對(duì)象短绸,了解過(guò)Cglib代理的同學(xué)都知道實(shí)現(xiàn)代理要實(shí)現(xiàn)MethodInterceptor接口,在里面的intercept方法中進(jìn)行方法的攔截筹裕。我們找到代理類(lèi)的intercept方法

首先調(diào)用getInterceptorsAndDynamicInterceptionAdvice方法獲取所有通知方法的Advisor攔截器鏈醋闭,chain不為空會(huì)依次調(diào)用對(duì)應(yīng)的Advisor攔截器的proceed方法進(jìn)行代理調(diào)用,在此會(huì)按照通知的順序執(zhí)行原方法與通知方法朝卒。

大體的執(zhí)行流程就分析完了证逻,有時(shí)間的同學(xué)最好簡(jiǎn)單寫(xiě)個(gè)demo然后跟著一步步debug,這樣能夠更清晰的了解流程抗斤。

最后總結(jié)一下囚企,容器初始化時(shí)將切面等信息放入通知集合中丈咐,正常bean在創(chuàng)建時(shí)會(huì)判斷該bean是否需要被增強(qiáng),若需要增強(qiáng)洞拨,創(chuàng)建相應(yīng)的代理對(duì)象扯罐。在執(zhí)行時(shí)负拟,代理對(duì)象執(zhí)行相應(yīng)的invoke方法烦衣,在方法中獲取到通知集合并抽象成攔截器鏈,使用攔截器模式按照順序執(zhí)行相應(yīng)的方法掩浙。

附兩張流程圖:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末花吟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子厨姚,更是在濱河造成了極大的恐慌衅澈,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谬墙,死亡現(xiàn)場(chǎng)離奇詭異今布,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)拭抬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)部默,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人造虎,你說(shuō)我怎么就攤上這事傅蹂。” “怎么了算凿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵份蝴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我氓轰,道長(zhǎng)婚夫,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任署鸡,我火速辦了婚禮案糙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘储玫。我一直安慰自己侍筛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布撒穷。 她就那樣靜靜地躺著匣椰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪端礼。 梳的紋絲不亂的頭發(fā)上禽笑,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天入录,我揣著相機(jī)與錄音,去河邊找鬼佳镜。 笑死僚稿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蟀伸。 我是一名探鬼主播蚀同,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼啊掏!你這毒婦竟也來(lái)了蠢络?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤迟蜜,失蹤者是張志新(化名)和其女友劉穎刹孔,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體娜睛,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡髓霞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了畦戒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片方库。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖兢交,靈堂內(nèi)的尸體忽然破棺而出薪捍,到底是詐尸還是另有隱情,我是刑警寧澤配喳,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布酪穿,位于F島的核電站,受9級(jí)特大地震影響晴裹,放射性物質(zhì)發(fā)生泄漏被济。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一涧团、第九天 我趴在偏房一處隱蔽的房頂上張望只磷。 院中可真熱鬧,春花似錦泌绣、人聲如沸钮追。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)元媚。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間刊棕,已是汗流浹背炭晒。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留甥角,地道東北人网严。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嗤无,于是被迫代替她去往敵國(guó)和親震束。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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