1. 程式人生 > 程式設計 >向您圖文並茂生動講解Spring AOP 原始碼(1)

向您圖文並茂生動講解Spring AOP 原始碼(1)

前言

Spring AOP - 註解方式使用介紹(長文詳解)中,作者介紹了Spring AOP 註解方式的使用方式。算是給咱們的Spring AOP 原始碼分析開了個頭,做了一點知識點的鋪墊。

在開始學習Spring AOP的原始碼之前,如果你還沒有學習過Spring IoC的原始碼,最好先去學習下Spring IoC。

Spring AOP 只作用於Spring Bean 的特性說明瞭Spring AOP和Spring IOC 的關係,AOP 依賴於 IOC 容器來管理,後面的原始碼分析也會涉及到Spring IoC 的原始碼內容。

下面,假設你已經學習過Spring IoC 的相關內容和Spring AOP的相關使用,讓我們開始吧。

本文耗費了作者大量心力,希望能對你有所幫助。

Spring AOP.png

我們前面一直說的Spring AOP原始碼解析,原始碼這麼多,我們真正關注的內容是什麼?

Spring AOP的功能是什麼?從使用上直白的說,就是根據我們的配置來生成代理類,攔截指定的方法,將指定的advice織入。

我們應該關注的內容總結下來就是:

  • Spring AOP 的觸發時機是什麼時候?
  • Spring AOP 是如何解析我們配置的Aspect,生成 Advisors 鏈的?
  • Spring AOP 是如何生成代理類的,如何將 advice 織入代理類?

另外,整個原始碼解析的內容過多,為了讀者的閱讀體驗和自己的時間安排。我將按照上面的總結的三點,分三篇向您解讀。

本文的原始碼解析是以AOP註釋方式使用來作為例子講解的,和其他方式主要是在於觸發入口不同,核心的流程還是差不多的。希望讀者們能夠觸類旁通。

一、開啟AOP自動代理的玄機

我們在Spring AOP - 註解方式使用介紹(長文詳解)中介紹了@EnableAspectJAutoProxy 註解,是用來開啟 Spring AOP註解的使用。這個的作用就是自動讓 ioc 容器中的所有 advisor 來匹配方法,advisor 內部都是有 advice 的,讓它們內部的 advice 來執行攔截處理(注:advisor 可以就看成 pointcut + advise的一個組合物件)。引用這個註解的英文翻譯就是開啟自動代理。

那麼裡面的玄機是什麼呢?

我們進去先進到這個註解裡面看看,

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;
    boolean exposeProxy() default false;
}
複製程式碼

@Import(AspectJAutoProxyRegistrar.class)使用@Import 註解將 AspectJAutoProxyRegistrar注入到 IoC 容器當中。

對這個註解不熟悉的可以去了解一下 @Import Annotation in Spring Framework

我們看一看這個AspectJAutoProxyRegistrar

AspectJAutoProxyRegistrar.png

注意,這個類實現了ImportBeanDefinitionRegistrar介面。

這個介面是一個Spring 很強大的擴充套件介面,它的作用是:

Register additional bean definitions when processing @Configuration classes. Useful when operating at the bean definition level (as opposed to @Bean method/instance level) is desired or necessary.

就是說,它需要和@Configuration配合使用,在@Configuration之前已註冊的Bean,可以由ImportBeanDefinitionRegistrar介面來處理,這個介面提供瞭如下一個方法:

void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry)
複製程式碼

這個方法可以拿到@Import的這個class的Annotation Metadata,以及此時的BeanDefinitionRegistry物件,通過BeanDefinitionRegistry 就可以拿到目前所有註冊的BeanDefinition,可以自定義邏輯來動態註冊一些你覺得必要的BeanDefinition。

PS: 很多開源框架與Spring 整合的時候都擴充套件了這個介面,比如Apollo的ApolloConfigRegistrar 、mybatis的MapperScannerRegistrar等等

擴充套件閱讀 www.logicbig.com/tutorials/s…

AspectJAutoProxyRegistrar中,實際上就是將AspectJAnnotationAutoProxyCreatorBeanDefinition註冊到IoC 容器當中。

下面是AopConfigUtils中執行註冊的邏輯程式碼片段。

image.png


先來一條分割線,理解完上面的流程之後,我們繼續來思考。

為什麼把AspectJAnnotationAutoProxyCreator注入到Spring IoC 容器中,自動代理就開啟了呢?

讓我們來尋找這個觸發點。

二、自動代理的觸發時機

首先,我們來看一下AspectJAnnotationAutoProxyCreator的繼承結構。

AnnatationAwareAspectJAutoProxyCreator.png

有沒有發現,AspectJAnnotationAutoProxyCreator居然是一個BeanPostProcessor

學習過 Spring IoC 之後的你,應該對這個類極其的敏感。

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean,String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean,String beanName) throws BeansException;
}
複製程式碼

我們先回顧思考下代理模式的實現思路:(介面) + 真實實現類 + 代理類

是不是要先有了真實的實現類,才能夠生成代理類?!

Spring IoC - 依賴注入 原始碼解析中我們介紹了Spring Bean 建立的過程,在執行完 Step1 建立例項物件createBeanInstance()和 Step2 屬性裝配populateBean()之後,我們才算得到一個真正的實現類

在Step3 initializeBean()中,IoC容器會處理Bean初始化之後的各種回撥事件,然後返回一個“可能經過加工”的bean物件。

其中就包括了BeanPostProcessorpostProcessBeforeInitialization 回撥 和 postProcessAfterInitialization 回撥。

AspectJAnnotationAutoProxyCreator恰恰是一個BeanPostProcessor(原諒我又重複了一次),那就很容易聯想到,Spring AOP 就是在這一步,進行代理增強

三、初探代理類的生成流程

那麼接下來,我們就來看看這裡面的玄機。

image.png

可以看到實際回撥的 postProcessBeforeInitializationpostProcessAfterInitialization 這兩個方式是在AbstractAdvisorAutoProxyCreator 中 override 的。

原始碼位置:AbstractAdvisorAutoProxyCreator

AbstractAdvisorAutoProxyCreator

JavaDoc 很清楚的註明瞭postProcessAfterInitialization會執行建立代理類的操作,用配置的interceptors 來建立一個代理類,並且告訴我們去看getAdvicesAndAdvisorsForBean,看來這會是一個關鍵方法,這裡我們先不急,繼續往下看wrapIfNecessary方法。

原始碼位置:AbstractAutoProxyCreator#wrapIfNecessary(..)

wrapIfNecessary

這個方法裡面有核心的就是兩個點,我在上圖中分別用**** TODO-1 ******** TODO-2 ****標識出來了。

TODO-1就是獲取當前的Spring Bean 適配的 advisors

TODO-2就是建立代理類


我們接下去的章節就是詳細講解這兩個TODO的內容。我們下次再會。

如果本文有幫助到你,希望能點個贊,這是對我的最大動力。