Spring之AOP原理

AOPSpring Core中幾大重要能力之一,我們可以使用AOP實現很多功能,比如我們常用的日誌處理與Spring中的聲明式事務。

AOP的重要概念:

1.Aspect:切面,在Spring中意爲所有通知方法所在的類
2.Join point:連接點,程序執行中的一點,在Spring中只表示方法執行(Spring只支持方法級別的攔截)
3.Advice:通知,在特定連接點上採取的操作,Spring將通知抽象爲攔截器,並圍繞連接點維護攔截器鏈。
4.Pointcut:切點,與通知一起出現,使用專門的切點表達式決定在何處執行通知方法。
5.Introduction:引入,爲類添加新的方法或字段。
6.Target object:被代理的對象
7.AOP proxy:AOP代理對象,由JDK動態代理或CGLIB代理生成
8.Weaving:織入,將通知等織入代理類。Spring AOP是動態織入(運行時織入),AspectJ則是靜態織入(編譯時織入)

注:五種通知類型:

1.before(切點之前執行),
2.around(環繞執行,即切點前後執行),
3.After returning(切點正常執行完返回後執行),
4.After throwing(切點拋出異常後執行),
5.after(切點之後執行,不管是異常或正常結束)

幾點注意:

  由於Spring AOP框架基於代理的特性,目標對象內的調用根據定義不會被攔截。
  自調用即類似this.bar()或this.foo()這樣的調用,即使在bar方法上有通知方法通知也不會執行。
  對於JDK代理,只能攔截代理上的公共接口方法調用。
  使用CGLIB,可以攔截代理上的公共和受保護方法調用(Cglib基於子父類實現代理,而私有方法不會被子類繼承)。
  當多個通知都想在同一個連接點上運行時,他們將按照優先級順序執行,優先級順序可以使用Order接口來定義。
總結一句:自調用通知方法不執行,私有方法通知不執行。

原理

接下來從源碼角度分析下Spring AOP的實現原理。

在Spring中我們使用@EnableAspectJautoProxy開啓AOP功能,我們以此爲入口。(其他的Enable註解分析原理都是一樣的,比如EnableAsync等)

 

 它使用@Import註解導入了AspectJAutoProxyRegistrar類,該類實現了ImportBeanDefinitionRegistrar接口,用於向Spring中註冊類。

 

 在registerBeanDefinitions方法的第一行註冊了AOP需要的相關bean,方法中的下面部分是取EnableAspectJAutoProxy註解的信息,根據參數值做相應的處理,這裏主要關注方法的首行代碼,進入registerAspectJAnnotationAutoProxyCreatorIfNecessary方法。

 

 發現最終註冊了AnnotationAwareAspectJAutoProxyCreator。該類是實現AOP的基礎,我們對該類進行分析,首先來看繼承結構

 

 BeanFactoryAware接口主要用於設置BeanFactory,這裏我們主要關注InstantiationAwareBeanPostProcessor與BeanPostProcessor接口,實現這兩個接口意味着AnnotationAwareAspectJAutoProxyCreator是一個Spring的後置處理器,後置處理器會在bean的創建過程中起作用,關於後置處理器不熟悉的同學可以去看這篇文章Spring之IOC容器初始化。

 

 InstantiationAwareBeanPostProcessor有一個before與after接口,由接口名可知兩個方法分別在bean實例化前後調用,關於Spring中bean的實例化過程不清楚的可以看Spring Bean的實例化分析。我們在子類中找到他們的實現(after方法由於沒有特別的處理這裏就省略了)

 

 

首先從緩存中獲取,然後調用this.isInfrastructureClass(beanClass)判斷創建的類是否爲Advice、Pointcut等相關類,若是則放入adviseBean集合並返回null,正常的bean經過該方法會返回null,這裏主要是用來處理我們的切面類。

 

 bean創建完成後接下來就是另一個接口BeanPostprocess(實例化,調用構造函數)開始起作用了。

 

 他會在InstantiationAwareBeanPostProcessor(初始化,即BeanDefination的初始化)接口方法執行完之後調用,查看其實現(before方法由於沒有特別的處理這裏就省略了)

 

 最終會調用wrapIfNecessary方法判斷該bean是否需要增強。進入方法

 

 正常bean的創建會進入到isInfrastructureClass這個分支,isInfrastructureClass這個方法就是之前分析的判斷是否是Aspect等註解的類,如果不是則調用getAdvicesAndAdvisorsForBean方法獲取到符合該bean的通知方法(即相應的Advisor)。

 

 最終調用createProxy創建代理對象。

 

 接上圖右側
最終進入代理工廠創建代理對象的方法,根據是否實現接口自動選擇創建JDK動態代理(基於接口)或者是Cglib代理(基於子父類)。到這裏切面以及要被代理的類就都創建完成了,接下來就是如何運行通知方法了。

執行流程

我們這裏假設上一步創建的對象爲Cglib對象,瞭解過Cglib代理的同學都知道實現代理要實現MethodInterceptor接口,在裏面的intercept方法中進行方法的攔截。我們找到代理類的intercept方法

 

 首先調用getInterceptorsAndDynamicInterceptionAdvice方法獲取所有通知方法的Advisor攔截器鏈,chain不爲空會依次調用對應的Advisor攔截器的proceed方法進行代理調用,在此會按照通知的順序執行原方法與通知方法。

 

 

大體的執行流程就分析完了,有時間的同學最好簡單寫個demo然後跟着一步步debug,這樣能夠更清晰的瞭解流程。

最後總結一下,容器初始化時將切面等信息放入通知集合中,正常bean在創建時會判斷該bean是否需要被增強,若需要增強,創建相應的代理對象。在執行時,代理對象執行相應的invoke方法,在方法中獲取到通知集合並抽象成攔截器鏈,使用攔截器模式按照順序執行相應的方法。

附兩張流程圖:

 

 

 參考博客:https://blog.csdn.net/u014735138/article/details/124072540

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章