向您圖文并茂生動講解Spring AOP 源碼(1)

前言

Spring AOP - 注解方式使用介紹(長文詳解)中奶陈,作者介紹了Spring AOP 注解方式的使用方式集嵌。算是給咱們的Spring AOP 源碼分析開了個頭少欺,做了一點知識點的鋪墊正压。

在開始學習Spring AOP的源碼之前瓷式,如果你還沒有學習過Spring IoC的源碼替饿,最好先去學習下Spring IoC。

Spring AOP 只作用于Spring Bean 的特性說明了Spring AOP和Spring IOC 的關系贸典,AOP 依賴于 IOC 容器來管理视卢,后面的源碼分析也會涉及到Spring IoC 的源碼內容。

下面廊驼,假設你已經(jīng)學習過Spring IoC 的相關內容和Spring AOP的相關使用据过,讓我們開始吧。

本文耗費了作者大量心力妒挎,希望能對你有所幫助绳锅。

Spring AOP.png

我們前面一直說的Spring AOP源碼解析,源碼這么多酝掩,我們真正關注的內容是什么鳞芙?

Spring AOP的功能是什么?從使用上直白的說期虾,就是根據(jù)我們的配置來生成代理類原朝,攔截指定的方法,將指定的advice織入镶苞。

我們應該關注的內容總結下來就是:

  • Spring AOP 的觸發(fā)時機是什么時候喳坠?
  • Spring AOP 是如何解析我們配置的Aspect,生成 Advisors 鏈的茂蚓?
  • Spring AOP 是如何生成代理類的壕鹉,如何將 advice 織入代理類?

另外煌贴,整個源碼解析的內容過多御板,為了讀者的閱讀體驗和自己的時間安排锥忿。我將按照上面的總結的三點牛郑,分三篇向您解讀。

本文的源碼解析是以AOP注釋方式使用來作為例子講解的敬鬓,和其他方式主要是在于觸發(fā)入口不同淹朋,核心的流程還是差不多的笙各。希望讀者們能夠觸類旁通。

一础芍、開啟AOP自動代理的玄機

我們在Spring AOP - 注解方式使用介紹(長文詳解)中介紹了@EnableAspectJAutoProxy 注解杈抢,是用來開啟 Spring AOP注解的使用。這個的作用就是自動讓 ioc 容器中的所有 advisor 來匹配方法仑性,advisor 內部都是有 advice 的惶楼,讓它們內部的 advice 來執(zhí)行攔截處理(注:advisor 可以就看成 pointcut + advise的一個組合對象)。引用這個注解的英文翻譯就是開啟自動代理诊杆。

那么里面的玄機是什么呢歼捐?

我們進去先進到這個注解里面看看,

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;
    boolean exposeProxy() default false;
}

@Import(AspectJAutoProxyRegistrar.class)使用@Import 注解將 AspectJAutoProxyRegistrar注入到 IoC 容器當中晨汹。

對這個注解不熟悉的可以去了解一下 @Import Annotation in Spring Framework

我們看一看這個AspectJAutoProxyRegistrar豹储,

AspectJAutoProxyRegistrar.png

注意,這個類實現(xiàn)了ImportBeanDefinitionRegistrar接口淘这。

這個接口是一個Spring 很強大的擴展接口剥扣,它的作用是:

Register additional bean definitions when processing @Configuration classes.
Useful when operating at the bean definition level (as opposed to @Bean method/instance level) is desired or necessary.

就是說,它需要和@Configuration配合使用铝穷,在@Configuration之前已注冊的Bean钠怯,可以由ImportBeanDefinitionRegistrar接口來處理,這個接口提供了如下一個方法:

void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)

這個方法可以拿到@Import的這個class的Annotation Metadata曙聂,以及此時的BeanDefinitionRegistry對象呻疹,通過BeanDefinitionRegistry 就可以拿到目前所有注冊的BeanDefinition,可以自定義邏輯來動態(tài)注冊一些你覺得必要的BeanDefinition筹陵。

PS: 很多開源框架與Spring 集成的時候都擴展了這個接口刽锤,比如Apollo的ApolloConfigRegistrar 、mybatis的MapperScannerRegistrar等等

擴展閱讀 https://www.logicbig.com/tutorials/spring-framework/spring-core/import-bean-registrar.html

AspectJAutoProxyRegistrar中朦佩,實際上就是將AspectJAnnotationAutoProxyCreatorBeanDefinition注冊到IoC 容器當中并思。

下面是AopConfigUtils中執(zhí)行注冊的邏輯代碼片段。

image.png

先來一條分割線语稠,理解完上面的流程之后宋彼,我們繼續(xù)來思考。

為什么把AspectJAnnotationAutoProxyCreator注入到Spring IoC 容器中仙畦,自動代理就開啟了呢输涕?

讓我們來尋找這個觸發(fā)點。

二慨畸、自動代理的觸發(fā)時機

首先试读,我們來看一下AspectJAnnotationAutoProxyCreator的繼承結構取逾。

AnnatationAwareAspectJAutoProxyCreator.png

有沒有發(fā)現(xiàn),AspectJAnnotationAutoProxyCreator居然是一個BeanPostProcessor居夹!

學習過 Spring IoC 之后的你,應該對這個類極其的敏感。

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

我們先回顧思考下代理模式的實現(xiàn)思路:(接口) + 真實實現(xiàn)類 + 代理類

是不是要先有了真實的實現(xiàn)類,才能夠生成代理類住册?!

Spring IoC - 依賴注入 源碼解析中我們介紹了Spring Bean 創(chuàng)建的過程瓮具,在執(zhí)行完 Step1 創(chuàng)建實例對象createBeanInstance()和 Step2 屬性裝配populateBean()之后荧飞,我們才算得到一個真正的實現(xiàn)類

在Step3 initializeBean()中名党,IoC容器會處理Bean初始化之后的各種回調事件垢箕,然后返回一個“可能經(jīng)過加工”的bean對象。

其中就包括了BeanPostProcessorpostProcessBeforeInitialization 回調 和 postProcessAfterInitialization 回調兑巾。

AspectJAnnotationAutoProxyCreator恰恰是一個BeanPostProcessor(原諒我又重復了一次)条获,那就很容易聯(lián)想到,Spring AOP 就是在這一步蒋歌,進行代理增強帅掘!

三、初探代理類的生成流程

那么接下來堂油,我們就來看看這里面的玄機修档。

image.png

可以看到實際回調的 postProcessBeforeInitializationpostProcessAfterInitialization 這兩個方式是在AbstractAdvisorAutoProxyCreator 中 override 的。

源碼位置:AbstractAdvisorAutoProxyCreator

AbstractAdvisorAutoProxyCreator

JavaDoc 很清楚的注明了postProcessAfterInitialization會執(zhí)行創(chuàng)建代理類的操作府框,用配置的interceptors 來創(chuàng)建一個代理類吱窝,并且告訴我們去看getAdvicesAndAdvisorsForBean,看來這會是一個關鍵方法迫靖,這里我們先不急院峡,繼續(xù)往下看wrapIfNecessary方法。

源碼位置:AbstractAutoProxyCreator#wrapIfNecessary(..)

wrapIfNecessary

這個方法里面有核心的就是兩個點系宜,我在上圖中分別用**** TODO-1 ******** TODO-2 ****標識出來了照激。

TODO-1就是獲取當前的Spring Bean 適配的 advisors

TODO-2就是創(chuàng)建代理類盹牧。


我們接下去的章節(jié)就是詳細講解這兩個TODO的內容俩垃。我們下次再會。

如果本文有幫助到你汰寓,希望能點個贊口柳,這是對我的最大動力。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末有滑,一起剝皮案震驚了整個濱河市跃闹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖辣卒,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掷贾,死亡現(xiàn)場離奇詭異睛榄,居然都是意外死亡荣茫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門场靴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來啡莉,“玉大人,你說我怎么就攤上這事旨剥∵中溃” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵轨帜,是天一觀的道長魄咕。 經(jīng)常有香客問我,道長蚌父,這世上最難降的妖魔是什么哮兰? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮苟弛,結果婚禮上喝滞,老公的妹妹穿的比我還像新娘。我一直安慰自己膏秫,他們只是感情好右遭,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缤削,像睡著了一般窘哈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上亭敢,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天宵距,我揣著相機與錄音,去河邊找鬼吨拗。 笑死满哪,一個胖子當著我的面吹牛,可吹牛的內容都是我干的劝篷。 我是一名探鬼主播哨鸭,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼娇妓!你這毒婦竟也來了像鸡?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎只估,沒想到半個月后志群,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡蛔钙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年锌云,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吁脱。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡桑涎,死狀恐怖,靈堂內的尸體忽然破棺而出兼贡,到底是詐尸還是另有隱情攻冷,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布遍希,位于F島的核電站等曼,受9級特大地震影響,放射性物質發(fā)生泄漏凿蒜。R本人自食惡果不足惜禁谦,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望篙程。 院中可真熱鬧枷畏,春花似錦、人聲如沸虱饿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氮发。三九已至渴肉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間爽冕,已是汗流浹背仇祭。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留颈畸,地道東北人乌奇。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像眯娱,于是被迫代替她去往敵國和親礁苗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354