當前位置:
首頁 > 科技 > 深入聊一聊 Spring AOP 實現機制!

深入聊一聊 Spring AOP 實現機制!

作者 | 張書康

責編 | 郭 芮

AOP(Aspect-Oriented Programming,即面向切面編程。Spring Aop 在 Spring框架中的地位舉足輕重,主要用於實現事務、緩存、安全等功能。本篇主要是對源碼進行深度分析。

Spring AOP 多種代理機制相關核心類介紹;

Spring Boot 中 AOP 註解方式源碼分析;

Spring Boot1.x版本和 2.x版本 AOP 默認配置的變動。

Spring AOP多種代理機制核心類

先介紹一些Spring Aop中一些核心類,大致分為三類:

advisorCreator:代理機制,抽象類AbstractAutoProxyCreator的每個實現類代表著一種代理機制。默認情況下只使用一種代理機制,繼承 spring ioc的擴展介面 beanPostProcessor,主要用來掃描獲取 advisor。

advisor:顧問的意思,advisor是Spring中切面的體現形式,封裝了spring aop中的切點和通知。

advice:通知,也就是 Spring AOP 中增強的方法。

以上三種核心類,來看對應的 UML圖。

advisorCreator:

AbstractAutoProxyCreator:代理機制抽象類,Spring 為Spring AOP 模塊暴露的擴展類,也是 AOP 中最核心的類。Nepxion Matrix 框架便是基於此類對AOP進行擴展和增強。

BeanNameAutoProxyCreator:根據指定名稱創建代理對象(阿里大名鼎鼎的連接池框架druid也基於此類做了擴展)。通過設置 advisor,可以對指定的 beanName 進行代理。支持模糊匹配。

AbstractAdvisorAutoProxyCreator:功能比較強大,默認掃描所有Advisor的實現類。相對於根據Bean名稱匹配,該類更加靈活。動態的匹配每一個類,判斷是否可以被代理,並尋找合適的增強類,以及生成代理類。

DefaultAdvisorAutoProxyCreator:AbstractAdvisorAutoProxyCreator的默認實現類。可以單獨使用,在框架中使用AOP,盡量不要手動創建此對象。

AspectJAwareAdvisorAutoProxyCreator:Aspectj的實現方式,也是Spring Aop中最常用的實現方式,如果用註解方式,則用其子類AnnotationAwareAspectJAutoProxyCreator。

AnnotationAwareAspectJAutoProxyCreator:目前最常用的AOP使用方式。spring aop 開啟註解方式之後,該類會掃描所有@Aspect()標準的類,生成對應的adviosr。目前SpringBoot框架中默認支持的方式,自動配置。

advisor:

StaticMethodMatcherPointcut:靜態方法切面,抽象類。定義了一個classFilter,通過重寫getClassFilter()方法來指定切面規則。另外實現了StaticMethodMatcher介面,通過重寫matches來指定方法匹配規則。

StaticMethodMatcherPointcutAdvisor:靜態方法匹配切面顧問,同未抽象類,擴展了切面排序方法。

NameMatchMethodPointcut:名稱匹配切面,通過指定方法集合變數mappedNames,模糊匹配。

NameMatchMethodPointcutAdvisor:方法名稱切面顧問,內部封裝了

NameMatchMethodPointcut,通過設置方法名稱模糊匹配規則和通知來實現切面功能。

RegexpMethodPointcutAdvisor:正則表達式切面顧問,可設置多個正則表達式規則,通過內部封裝的

JdkRegexpMethodPointcut解析正則表達式。

DefaultPointcutAdvisor:默認切面顧問,比較靈活。可自由組合切面和通知。

InstantiationModelAwarePointcutAdvisorImpl:springboot自動裝配的顧問類型,也是最常用的一種顧問實現。在註解實現的切面中,所有@Aspect注釋的類,都會被解析成該對象。

advice:

AspectJMethodBeforeAdvice:前置通知,AspectJ中 before 屬性對應的通知(@Before標註的方法會被解析成該通知),在切面方法執行之前執行。

AspectJAfterReturningAdvice:後置通知,AspectJ中 afterReturning 屬性對應的通知(@AfterReturning 標註的方法會被解析成該通知),在切面方法執行之後執行,如果有異常,則不執行。注意:該通知與AspectJMethodBeforeAdvice對應。

AspectJAroundAdvice:環繞通知,AspectJ中 around 屬性對應的通知(@Around標註的方法會被解析成該通知),在切面方法執行前後執行。

AspectJAfterAdvice:返回通知,AspectJ中 after 屬性對應的通知(@After 標註的方法會被解析成該通知),不論是否異常都會執行。

可以看出 Spring AOP 提供的實現方式很多,但是殊途同歸。

具體使用方式已上傳至 github:https://github.com/admin801122/springboot2-spring5-studying。

Spring Boot 中AOP註解方式源碼分析

Spring Aop使用方式很多,從上面的 API 也可以看出。本篇就基於最常用的註解實現方式,對源碼深入分析。

這是實際項目中使用AOP最常見的形式,基於註解實現。如今springboot大行其道,我們就從springboot中的EnableAspectJAutoProxy自動配置開始。

大致流程主要分為三個步驟:

一: 創建AnnotationAwareAspectJAutoProxyCreator對象;

二: 掃描容器中的切面,創建PointcutAdvisor對象;

三: 生成代理類。

分別來分析以上三個步驟。

1: 創建 AbstractAutoProxyCreator 對象

基於註解實現的 AOP 默認註冊 AbstractAutoProxyCreator 對象實現類為:AnnotationAwareAspectJAutoProxyCreator,來看一下該對象的創建過程。先從spring.factories開始:

具體來看:

(1)該配置類的載入前提是什麼?

繼續跟進EnableAspectJAutoProxy:

上述代碼可以看到註冊了一個切面相關BeanDefinition,正是上面提到的類:

AnnotationAwareAspectJAutoProxyCreator,並設置了代理方式配置變數: proxyTargetClass,默認為true。

這裡只是創建BeanDefinition,並沒有實例化和初始化該對象。那什麼時候會觸發呢?

上面的 uml 圖可以看到,該類繼承的頂層介面為 BeanPostProcessor。我們知道BeanPostProcessor實現類會提前初始化,由PostProcessorRegistrationDelegate觸發,具體細節這篇文章《SpringBoot2 | @SpringBootApplication註解,自動化配置流程源碼分析》有提到。

該類又繼承BeanFactoryAware,所以在其在實例化 bean 後,會觸發setBeanFactory()方法,最終會觸發initBeanFactory方法:

最終 Advisor 對象就是由aspectJAdvisorsBuilder 生成。

至此,AnnotationAwareAspectJAutoProxyCreator BeanDefinition創建完畢。

2: 掃描容器中的切面,創建 PointcutAdvisor對象

在spring ioc流程載入的過程中,會觸發 beanPostProcessor 擴展介面,

而AnnotationAwareAspectJAutoProxyCreator又是SmartInstantiationAwareBeanPostProcessor的子類,所以該擴展介面正是 aop 實現的入口。

該介面的觸發在實例化 bean 之後,初始化 bean之前,具體來看:

來看一下判定 bean 是否被代理的方法依據:

重點來看 shouldSkip方法:

上述代碼通過findCandidateAdvisors()方法來獲取所有的候選 advisor:

繼續跟進buildAspectJAdvisors方法,會觸發ReflectiveAspectJAdvisorFactory中的getAdvisors方法:

繼續來看getAdvisor方法:

可以看到方法將切面相關的類,封裝成InstantiationModelAwarePointcutAdvisorImpl對象,也就是Advisor 對象。

來看下上面獲取切面的方法,規則就是遍歷方法,根據註解判斷:

我們繼續來看 Advisor 對象的構造方法。

可以看到,根據@Aspect類中方法的註解類型,生成對應的advice,並通過通知的構造方法,將通知增強方法,切面表達式傳入到通知當中。

InstantiationModelAwarePointcutAdvisorImpl對象到這裡構造完畢。

3: 生成代理類

上面創建advisor的邏輯發生在擴展介面中的postProcessBeforeInstantiation,實例化之前執行,如果有自定義的TargetSource指定類,則則直接生成代理類,並直接執行初始化之後的方法postProcessAfterInitialization。這種情況使用不多,常規代理類還是在postProcessAfterInitialization中創建,也就是 IOC 最後一個擴展方法。

上述方法通過調用getAdvicesAndAdvisorsForBean()方法來獲取advisor,該方法最終會調用findEligibleAdvisors(),Eligible意為有資格的,合適的。具體來看下:

最終的篩選規則在AopUtils中:

調用canApply方法,遍歷被代理類的所有的方法,跟進切面表達式進行匹配,如果有一個方法匹配到,也就意味著該類會被代理。

重點來看一下代理生成方式:

上述方法通過三個變數來進行篩選代理方法:

optimize:官方文檔翻譯為設置代理是否應執行積極的優化,默認為false。

proxyTargetClass:這個在上面已經提到了,AopAutoConfiguration中指定,默認為true,也就是選擇使用 cglib 代理。可以看到該變數和optimize意義一樣,之所以這麼做,個人理解是為了可以在不同的場景中使用。

hasNoUserSuppliedProxyInterfaces:是否指定了實現介面。什麼意思呢?

hasNoUserSuppliedProxyInterfaces方法如下:

主要就是判斷AdvisedSupport中interfaces變數中是否設置了介面,意思是如果一個類實現了介面,把介面設置到該方法的變數中,但是不是一定會設置到該變數中,具體設置介面的代碼如下:

可以看到如果proxyTargetClass為 true,上述方法將不再執行,也就意味著interfaces變數不再賦值。同時,只要為類代理,默認會走 CGLIB 方式。

Spring Boot 1.x 版本和 2.x 版本中 AOP配置變動

配置類AopAutoConfiguration:

1.5x版本:

2.x版本:

在SpringBoot2.x中最主要的變化就是proxy-target-class默認為true,意味著類代理的時候全部走cglib代理方式,只有為介面代理時才走jdk代理(注意:這裡為介面代理,不是指代理目標類是否實現了介面)。

所以,在使用springboot2.x的版本中,除了代理目標類是介面外,其餘的代理方式全部採用cglib類型。

總結

Springboot通過自動裝配AopAutoConfiguration配置類,默認自動開啟 AOP 功能。

通過註冊AnnotationAwareAspectJAutoProxyCreator類,來掃描創建所有的Advisor,再通過 Advisor在 Spring IOC的擴展介面中,通過各種設置的匹配規則,來判斷是否設置代理,最終生成代理類,注入容器 Spring中。

聲明:本文為作者投稿,版權歸其個人所有。

【完】

熱 文推 薦


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 CSDN 的精彩文章:

程序員如何玩轉彙編指令?
互聯網寒冬下,為什麼就你被裁了?

TAG:CSDN |