深入聊一聊 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中。
聲明:本文為作者投稿,版權歸其個人所有。
【完】
熱 文推 薦


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