前言
在Spring AOP - 注解方式使用介紹(長文詳解)中奶陈,作者介紹了Spring AOP 注解方式的使用方式集嵌。算是給咱們的Spring AOP 源碼分析開了個頭少欺,做了一點知識點的鋪墊正压。
在開始學習Spring AOP的源碼之前瓷式,如果你還沒有學習過Spring IoC的源碼替饿,最好先去學習下Spring IoC。
Spring AOP 只作用于Spring Bean 的特性說明了Spring AOP和Spring IOC 的關系贸典,AOP 依賴于 IOC 容器來管理视卢,后面的源碼分析也會涉及到Spring IoC 的源碼內容。
下面廊驼,假設你已經(jīng)學習過Spring IoC 的相關內容和Spring AOP的相關使用据过,讓我們開始吧。
本文耗費了作者大量心力妒挎,希望能對你有所幫助绳锅。
我們前面一直說的Spring AOP源碼解析,源碼這么多酝掩,我們真正關注的內容是什么鳞芙?
Spring AOP的功能是什么?從使用上直白的說期虾,就是根據(jù)我們的配置來生成代理類原朝,攔截指定的方法,將指定的advice織入镶苞。
我們應該關注的內容總結下來就是:
- Spring AOP 的觸發(fā)時機是什么時候喳坠?
- Spring AOP 是如何解析我們配置的Aspect,生成 Advisors 鏈的茂蚓?
- Spring AOP 是如何生成代理類的壕鹉,如何將 advice 織入代理類?
另外煌贴,整個源碼解析的內容過多御板,為了讀者的閱讀體驗和自己的時間安排锥忿。我將按照上面的總結的三點牛郑,分三篇向您解讀。
本文的源碼解析是以AOP注釋方式使用來作為例子講解的敬鬓,和其他方式主要是在于觸發(fā)入口不同淹朋,核心的流程還是差不多的笙各。希望讀者們能夠觸類旁通。
一础芍、開啟AOP自動代理的玄機
我們在Spring AOP - 注解方式使用介紹(長文詳解)中介紹了@EnableAspectJAutoProxy
注解杈抢,是用來開啟 Spring AOP注解的使用。這個的作用就是自動讓 ioc 容器中的所有 advisor 來匹配方法仑性,advisor 內部都是有 advice 的惶楼,讓它們內部的 advice 來執(zhí)行攔截處理(注: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
豹储,
注意,這個類實現(xiàn)了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,可以自定義邏輯來動態(tài)注冊一些你覺得必要的BeanDefinition筹陵。
PS: 很多開源框架與Spring 集成的時候都擴展了這個接口刽锤,比如Apollo的ApolloConfigRegistrar 、mybatis的MapperScannerRegistrar等等
擴展閱讀 https://www.logicbig.com/tutorials/spring-framework/spring-core/import-bean-registrar.html
在AspectJAutoProxyRegistrar
中朦佩,實際上就是將AspectJAnnotationAutoProxyCreator
的BeanDefinition
注冊到IoC 容器當中并思。
下面是AopConfigUtils
中執(zhí)行注冊的邏輯代碼片段。
先來一條分割線语稠,理解完上面的流程之后宋彼,我們繼續(xù)來思考。
為什么把AspectJAnnotationAutoProxyCreator
注入到Spring IoC 容器中仙畦,自動代理就開啟了呢输涕?
讓我們來尋找這個觸發(fā)點。
二慨畸、自動代理的觸發(fā)時機
首先试读,我們來看一下AspectJAnnotationAutoProxyCreator
的繼承結構取逾。
有沒有發(fā)現(xiàn),AspectJAnnotationAutoProxyCreator
居然是一個BeanPostProcessor
居夹!
學習過 Spring IoC 之后的你,應該對這個類極其的敏感。
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
我們先回顧思考下代理模式的實現(xiàn)思路:(接口) + 真實實現(xiàn)類 + 代理類。
是不是要先有了真實的實現(xiàn)類,才能夠生成代理類住册?!
在Spring IoC - 依賴注入 源碼解析中我們介紹了Spring Bean 創(chuàng)建的過程瓮具,在執(zhí)行完 Step1 創(chuàng)建實例對象createBeanInstance()
和 Step2 屬性裝配populateBean()
之后荧飞,我們才算得到一個真正的實現(xiàn)類。
在Step3 initializeBean()
中名党,IoC容器會處理Bean初始化之后的各種回調事件垢箕,然后返回一個“可能經(jīng)過加工”的bean對象。
其中就包括了BeanPostProcessor
的 postProcessBeforeInitialization
回調 和 postProcessAfterInitialization
回調兑巾。
而AspectJAnnotationAutoProxyCreator
恰恰是一個BeanPostProcessor
(原諒我又重復了一次)条获,那就很容易聯(lián)想到,Spring AOP 就是在這一步蒋歌,進行代理增強帅掘!
三、初探代理類的生成流程
那么接下來堂油,我們就來看看這里面的玄機修档。
可以看到實際回調的 postProcessBeforeInitialization
和 postProcessAfterInitialization
這兩個方式是在AbstractAdvisorAutoProxyCreator
中 override 的。
源碼位置:AbstractAdvisorAutoProxyCreator
JavaDoc 很清楚的注明了postProcessAfterInitialization
會執(zhí)行創(chuàng)建代理類的操作府框,用配置的interceptors 來創(chuàng)建一個代理類吱窝,并且告訴我們去看getAdvicesAndAdvisorsForBean
,看來這會是一個關鍵方法迫靖,這里我們先不急院峡,繼續(xù)往下看wrapIfNecessary
方法。
源碼位置:AbstractAutoProxyCreator#wrapIfNecessary(..)
這個方法里面有核心的就是兩個點系宜,我在上圖中分別用**** TODO-1 ****
和**** TODO-2 ****
標識出來了照激。
TODO-1
就是獲取當前的Spring Bean 適配的 advisors。
TODO-2
就是創(chuàng)建代理類盹牧。
我們接下去的章節(jié)就是詳細講解這兩個TODO
的內容俩垃。我們下次再會。
如果本文有幫助到你汰寓,希望能點個贊口柳,這是對我的最大動力。