1. 程式人生 > 其它 >Spring原始碼-學習隨筆(一)AOP代理實現的切入口

Spring原始碼-學習隨筆(一)AOP代理實現的切入口

首先了解在沒有Springboot的spring專案中,aop是如何啟用的。

一、

  首先需要@EnableAspectJAutoProxy配合@Configuration 在spring中開啟aop,所以起點在這個註解中,首先研究這個註解大概做了什麼

重點在那個import的類中,從名字中可以猜出,是實現了介面,然後通過beanRegistrar將bean的定義資訊註冊到beanFactory中,然後等待建立

一開始,bean的定義資訊中肯定沒有internalAutoProxyCreator這個beanName,所以最終註冊一個name是internalAutoProxyCreator的AnnotationAwareAspectJAutoProxyCreator的bean定義資訊

這個就是這個註解的作用,用來註冊一個ProxyCreator,從名字猜一下就是建立代理的。

二、

  接下來看看在springBoot中,AOP的入口在哪裡。

  因為在springBoot中使用aop的時候,我們並不需要新增上述的那個註解,一般都是直接新增相應的starter依賴,然後就可以使用了,這涉及springboot的自動配置原理,有興趣可以去了解,這裡直接說結果。

我們在自動配置檔案spring.factoryies中發現該類 EnableAutoConfiguration --> AopAutoConfiguration

從類中可以看到,只要存在類Advice,自動配置就會開啟,然後可以發現,預設開啟的代理模式是cglib的代理,在這裡出現了@EnableAspectJAutoProxy註解,所以同樣的,自動開啟了AOP

然後還會發現,出現一個ClassProxyingConfiguration,也同樣的會呼叫一個相似的方法來建立ProxyCreator

進去之後,發現最終呼叫的方法一樣,但是引數不一致,但是在此時,因為@EnableAspectJAutoProxy註解,我們的ProxyCreator已經建立了,所以回顧上文的這個方法,我們會進入if中,將已經建立的ProxyCreator與我們希望建立的ProxyCreator比較優先順序,決定最終容器中的ProxyCreator,也就是我們可以通過實現這個自定義的ProxyCreator來覆蓋spring提供的預設ProxyCreator

三、

  那麼入口知道了,我們開始研究一下AnnotationAwareAspectJAutoProxyCreator這個類,是如何在bean的建立過程中完成代理的。

首先看下這個類的繼承樹:

可以發現,這個類主要的代理功能肯定是在主幹的抽象類中,然後我們還看到它還實現了BeanPostProcessor型別介面,這也就意味著,這個ProxyCreator的執行時機是在Bean的建立前後或者初始化前後。

接下來以此為切入口,繼續分析整個繼承樹中,BeanPostProcessor介面的方法的實現在哪一層,進一步猜測這個類的執行時機。

檢視之後可以看到,介面的實現集中在這個抽象類中,而且有作用的實現方法只有兩個,以此得出,代理的建立時機只有兩個地方,分別是bean例項化之前和bean初始化之後。

AbstractAutoProxyCreator --> postProcessBeforeInstantiation(InstantiationAwareBeanPostProcessor)
AbstractAutoProxyCreator --> postProcessAfterInitialization(BeanPostProcessor

AbstractAutoProxyCreator --> getEarlyBeanReference(SmartInstantiationAwareBeanPostProcessor)

然後我們可以簡單看下,這個代理的建立過程,都是集中在createProxy方法中

createAopProxy

接著將建立的AopProxy呼叫getProxy

然後代理建立完畢。

四、

  接著,將在容器啟動過程中,bean的建立過程中,分析aop的建立時機

無論是spring原生專案還是springboot構建的專案,最終bean的建立還是會回到AbstractApplicationContext --> refresh() 方法中

在普通的bean的建立之前,會把bean定義資訊中是beanPostProcessor介面的都創建出來,我們之前通過@EnableAspectJAutoProxy註解註冊在bean定義資訊中的AnnotationAwareAspectJAutoProxyCreator也就會被建立了

然後就是將bean定義資訊中,所有未建立的單例bean全部建立

在createBean方法中,出現第一個aop代理的入口,應用InstantiationAwareBeanPostProcessor的介面方法,在bean例項化之前,返回一個代理bean。

不過,在平時的應用中,我暫時還沒碰見應用這個方法的場景,暫時不知道這個入口會在什麼時候被觸發

然後進入真正的bean的建立

在doCreateBean中,出現第二個aop代理的入口,該程式碼位於bean的例項化之後,初始化之前,在這裡target會被提前暴露在一級快取,並且提供的方法是

SmartInstantiationAwareBeanPostProcessor介面的實現方法。可以猜測,這裡暴露之後,在target初始化setter依賴注入的時候,發生迴圈依賴時,對方在獲取到一級快取中的方法並獲取target的時候,拿到的是aop代理,而不是target

bean例項化之後,賦值完成之後,會對bean初始化

在這裡出現第三的aop代理的入口,應用的方法是BeanPostProcessor介面的方法,在對bean初始化完成之後,進行aop代理

五、

至此,目前發現的aop的入口有三處,分別是bean例項化之前,例項化之後和初始化賦值之前,以及初始化之後。

第一種情況的應用場景還沒搞清楚,暫且不說;

第二種情況是在target出現迴圈依賴的情況下,提前暴露一個aop代理的建立方法,這樣可以保證依賴的bean拿到的是代理而不是本體;

第三情況是我遇到最多的,而且我的程式碼中都是使用的構造器注入,而構造器注入是不會有迴圈依賴的情況的

以上內容只是簡述了aop代理的原理和切入口,還有一些其他的細節沒有詳述,例如aop的增強器是如何獲取的,如何和target包裝在一起的,aop的入口是不是隻有這三個入口等等。

如有錯漏,歡迎指正。