TL;DR#
- @EnableAspectJAutoProxy 開啟自動代理
- Context 啟動會創建 AnnotationAwareAspectJAutoProxyCreator 的 BeanDefinition 放到「BeanFactory」中的「beanDefinitionMap」
- 創建的 bean 實例放到「BeanFactory」中的「singletonObjects」和「beanPostProcessors」
- 前置處理,掃描所有 Aspect,生成所有的 Advisor,放入快取
- 在創建 Bean 流程中的「實例化 Bean 的前置處理階段」,掃描所有
@Aspect
修飾的類,生成「Advisor (Advice + Pointcut)」列表,並快取 advisorsCahce 中
- 在創建 Bean 流程中的「實例化 Bean 的前置處理階段」,掃描所有
- 創建 Proxy Bean (JDK Proxy 或 cglib 實現)
- 一般情況,在創建 Bean 流程中的「初始化 bean 的後置處理階段」,但是在「循環依賴」情況下,會提前 AOP,在「填充 bean 屬性階段」,提前創建 Proxy Bean
- 檢查 Advisor 的 Pointcut 條件是否與 bean 對應類中任一方法「匹配」,存在匹配情況,若匹配放入 「eligibleAdvisors」 列表
- 若「eligibleAdvisors」列表不為空,說明需要 AOP,進而創建 Proxy Bean,放入「BeanFactory」
ProxyBean
->AopProxy (JDK or Cglib)
->ProxyFacotry (advised)
->eligibleAdvisors
- Proxy Bean 調用代理方法,調用「攔截器鏈」鏈式執行「Advice」的方法
- 獲取「Target Bean」和被調用方法所匹配的「攔截器鏈 (
Advisor
<->MethodInterceptor
)」 - 通過創建 ReflectiveMethodInvocation 實例,遞歸調用 proceed 方法,遍歷「攔截器鏈」,進行反射調用「攔截器」的 Advice 方法
- ReflectiveMethodInvocation 實例通過維護 currentInterceptorIndex 索引來遍歷「攔截器鏈」,當遍歷完「攔截器鏈」會調用 invokeJoinpoint 方法,調用「Target Bean」的目標方法。
- 獲取「Target Bean」和被調用方法所匹配的「攔截器鏈 (
什麼是 AOP?#
- AOP (Aspect Oriented Programming, 面向切面編程) 是一種「編程範式」
- 本質是將「核心功能」與「切面功能」進行「解耦」,可分別獨立進行開發功,然後將「核心功能」和「切面功能」進行「織入 Weaving」
什麼是 Spring AOP?#
- 結合 Spring IOC 容器,通過在創建 Bean 過程中進行增強,生成 Proxy Bean,實現在程序 Runtime 期間,「動態」地將「核心功能」和「切面功能」進行「織入 Weaving」
- 本質就是,通過「代理模式 (動態代理)」實現 AOP,並結合 Spring IOC 容器,存放 Proxy Bean
相關概念#
- Jointpoint: 連接點 (方法執行,異常處理)
- Pointcut: 切點
- Advice: 在 Jointpoint 執行的「切面功能」操作
也叫「通知」,包括 Around, Before, After, AfterReturning, AfterThrowing
- Advisor: Pointcut + Advice
Spring AOP 的工作流程#
-
開啟 AspectJ 註解自動代理
生成 AnnotationAwareAspectJAutoProxyCreator 的 bean 實例,放入「BeanFactory」中的「beanDefinitionMap」,「singletonObjects」和「beanPostProcessors」
- Spring AOP 開啟 AspectJ 自動代理對應的註解是
@EnableAspectJAutoProxy
,通過註解@Import
導入 AspectJAutoProxyRegistrar - AspectJAutoProxyRegistrar 作用是將 AnnotationAwareAspectJAutoProxyCreator 生成對應的 BeanDefinition 對象,放入到 BeanDefinition 註冊中心中
- AnnotationAwareAspectJAutoProxyCreator
- 根據 BeanDefinition 創建 AnnotationAwareAspectJAutoProxyCreator 的 Bean 對象,並加入到 BeanFactory 的 beanPostProcessors (Bean 處理器列表) 中
- 實現了 SmartInstantiationAwareBeanPostProcessor 接口,重要的方法如下
- Bean 初始化前置處理方法: postProcessBeforeInitialization()
- 獲取早期 Bean 引用: getEarlyBeanReference()
- Bean 初始化後置處理方法: postProcessAfterInitialization()
- Spring AOP 開啟 AspectJ 自動代理對應的註解是
-
前置準備
查找所有「切面 Aspect」類來生成「Advisor (Advice + Pointcut)」列表,並快取起來
- 在創建 Bean 的流程,在「實例化 Bean」之前的階段 「resolveBeforeInstantiation」
- 在第一次調用 AnnotationAwareAspectJAutoProxyCreator 的 bean 實例的postProcessBeforeInstantiation 方法
- 從「BeanFacotry」中獲取所有的 Bean Name,遍歷 Bean Name 列表,根據 beanName 查詢「beanDefinitonMap」對應的類,是否含有
@Aspect
註解 - 對含有
@Aspect
的類,掃描其所有的「Advice」方法和對應的「Pointcut」方法,生成「Advisor」列表 - 將「Advisor」列表快取到
advisorCache
Map 中
- 從「BeanFacotry」中獲取所有的 Bean Name,遍歷 Bean Name 列表,根據 beanName 查詢「beanDefinitonMap」對應的類,是否含有
-
創建 Proxy Bean
若在創建 Bean 過程,與「Advisor」集合任意匹配成功,創建 AOP 代理對象
-
一般情況,進行 AOP 創建 Proxy Bean,是在「初始化 bean 後置處理階段」
- 在創建 bean 流程的「初始化 bean 後置處理階段」
- 調用 AnnotationAwareAspectJAutoProxyCreator 的 bean 實例的 postProcessAfterInitialization 方法,調用 wrapIfNecessary 方法創建 Proxy Bean
- 從「advisorsCache」獲取所有的 Advisor,通過查看當前需要創建的 bean 的類中,是否有任一方法與「Advisor 的 Pointcut 條件」匹配,從而篩選出匹配的「eligibleAdvisors」列表
- 創建 ProxyFactory 實例
- 將「匹配 advisor 列表」設置到 ProxyFactory 的「advisors」屬性中
- 將包裝了「實例化的 bean」的 SingletonTargetSource 實例設置到 ProxyFactory 的「targetSource」屬性中
- 調用 ProxyFactory 實例的 createAopProxy 方法,根據條件選擇創建 AopProxy 實例
- 「JdkDynamicAopProxy」
- 「ObjenesisCglibAopProxy」
- 調用 Aop Proxy 實例的 getProxy 方法的實現 (JDK 或 Cglib),創建「Proxy Bean」
- 將 Proxy Bean 放入到「BeanFactory 容器」的「singletonObjects」中
-
在有「循環依賴」下,需提前進行 AOP,提前創建 Proxy Bean,是在「填充 bean 屬性階段」
Mermaid Loading...- 在創建 bean 流程的「填充 bean 屬性階段」
- 調用 AnnotationAwareAspectJAutoProxyCreator 的 bean 實例的 getEarlyBeanReference 方法,進行提前 AOP,調用 wrapIfNecessary 方法創建 Proxy Bean
- 創建 Proxy Bean 與一般情況一樣,詳情看上述一般情況
-
-
Proxy Bean 調用代理方法,調用「攔截器鏈」鏈式執行「Advice」方法
- 調用 Proxy Bean 實例的方法,調用代理方法
- JDK 代理,調用的是 JdkDynamicAopProxy (InvocationHandler) 的 invoke 方法
- Cglib 代理,調用的是 ObjenesisCglibAopProxy 的 intercept 方法
- 從 advised (即 ProxyFactory) 中取出「原始 Bean (Target Bean)」
- 構建與「被調用方法 callee method」所匹配的「攔截器鏈」
- 從 advised (即 ProxyFactory) 中的與 bean 的類所匹配的所有的 「Advisor」
- 然後遍歷檢查「Advisor」是否與當前方法匹配
- 與當前方法匹配的「Advisor」,進行構建出對應的「Interceptor 攔截器」,放入「攔截器鏈」列表中
- 快取和返回「攔截器鏈」
- 構建 MethodInvocation,包裝 Proxy Bean, Target Bean, 「攔截器鏈」等,執行「攔截器鏈」
- 根據不同代理創建不同的 MethodInvocation,遞歸調用 proceed 方法
- JDK 代理,創建 ReflectiveMethodInvocation,進行遞歸調用 ReflectiveMethodInvocation 的 proceed 方法
- Cglib 代理,創建 CglibMethodInvocation,進行遞歸調用 ReflectiveMethodInvocatio 的 proceed 方法 (CglibMethodInvocation 繼承了 ReflectiveMethodInvocatio)
- 通過反射調用「攔截器」的 Advice 方法
- ReflectiveMethodInvocation 實例通過維護 currentInterceptorIndex 索引來遍歷「攔截器鏈」
- 如果已執行完「攔截器鏈」,調用 ReflectiveMethodInvocatio 的 invokeJoinpoint 方法,反射調用「原始 Bean (Target Bean)」的方法 (被代理)
- 根據不同代理創建不同的 MethodInvocation,遞歸調用 proceed 方法
- 調用 Proxy Bean 實例的方法,調用代理方法
攔截器與 Advice 和註解的關係#
@Around
- Advice 和攔截器: AspectJAroundAdvice
@Before
- 適配器: MethodBeforeAdviceAdapter
- Advice: AspectJMethodBeforeAdvice->MethodBeforeAdvice
- 攔截器: MethodBeforeAdviceInterceptor
@After
- Advice 和攔截器: AspectJAfterAdvice
@AfterReturning
- 適配器: MethodBeforeAdviceAdapter
- Advice: AspectJAfterReturningAdvice->AfterReturningAdvice
- 攔截器: AfterReturningAdviceInterceptor
@AfterThrowing
- Advice 和攔截器: AspectJAfterThrowingAdvice
- ThrowsAdviceAdapter 適配器,沒有對應的註解
- Advice: ThrowsAdvice
- 攔截器: ThrowsAdviceInterceptor
「攔截器鏈」執行過程的時序圖#
Mermaid Loading...