1. 程式人生 > >【Spring註解驅動開發】二狗子讓我給他講講@EnableAspectJAutoProxy註解

【Spring註解驅動開發】二狗子讓我給他講講@EnableAspectJAutoProxy註解

## 寫在前面 > 最近,二狗子入職了新公司,新入職的那幾天確實有點飄。不過慢慢的,他發現他身邊的人各個身懷絕技啊,有Spring原始碼的貢獻者,有Dubbo原始碼的貢獻者,有MyBatis原始碼的貢獻者,還有研究AI的大佬,個個都是大神級別的人物。二狗子有點慌,想起自己雖然入職了,但是比起其他人確實差點遠啊。怎麼辦呢?先從基礎補起唄,他發現自己對於Spring的理解還不算太深。於是乎,他讓我給他講講Spring的@EnableAspectJAutoProxy註解。 ># > 好吧,二狗子要請我吃飯啊!關注 **冰河技術** 微信公眾號,後臺回覆“Spring註解”領取工程原始碼。 ># > 如果文章對你有點幫助,請點個贊,給個在看和轉發,大家的三連是我持續創作的最大動力! ## @EnableAspectJAutoProxy註解 在配置類上新增@EnableAspectJAutoProxy註解,能夠開啟註解版的AOP功能。也就是說,AOP中如果要使註解版的AOP功能起作用,就需要在配置類上新增@EnableAspectJAutoProxy註解。 我們先來看下@EnableAspectJAutoProxy註解的原始碼,如下所示。 ```java package org.springframework.context.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { boolean proxyTargetClass() default false; boolean exposeProxy() default false; } ``` 從原始碼可以看出,@EnableAspectJAutoProxy使用@Import註解引入了AspectJAutoProxyRegister.class物件 。那麼,AspectJAutoProxyRegistrar又是什麼呢?我們繼續點選到AspectJAutoProxyRegistrar類的原始碼中,如下所示。 ```java package org.springframework.context.annotation; import org.springframework.aop.config.AopConfigUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null) { if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } } ``` 可以看到AspectJAutoProxyRegistrar類實現了ImportBeanDefinitionRegistrar介面。看下ImportBeanDefinitionRegistrar介面的定義,如下所示。 ```java package org.springframework.context.annotation; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.core.type.AnnotationMetadata; public interface ImportBeanDefinitionRegistrar { default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { registerBeanDefinitions(importingClassMetadata, registry); } default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { } ``` 看到ImportBeanDefinitionRegistrar介面,小夥伴們是不是覺得很熟悉呢。沒錯,我們在【Spring註解驅動開發】專題前面的文章中介紹過。可以通過ImportBeanDefinitionRegistrar介面實現將自定義的元件新增到IOC容器中。 也就說,**@EnableAspectJAutoProxy註解使用AspectJAutoProxyRegistrar物件自定義元件,並將相應的元件新增到IOC容器中。** ## 除錯Spring原始碼 我們在AspectJAutoProxyRegistrar類的registerBeanDefinitions()方法中設定斷點,如下所示。 ![](https://img-blog.csdnimg.cn/20200902215649906.png) 接下來,我們以debug的方法來執行AopTest類的testAop01()方法。執行後程序進入到斷點位置,如下所示。 ![](https://img-blog.csdnimg.cn/20200902215701199.png) 可以看到,程式已經暫停在斷點位置,而且在IDEA的左下角顯示了方法的呼叫棧。 在AspectJAutoProxyRegistrar類的registerBeanDefinitions()方法,首先呼叫AopConfigUtils類的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法來註冊registry。單看registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法也不難理解,字面含義就是:如果需要的話註冊一個AspectJAnnotationAutoProxyCreator。 接下來,我們進入到AopConfigUtils類的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,如下所示。 ![](https://img-blog.csdnimg.cn/20200902215713440.png#pic_center) 在AopConfigUtils類的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,直接呼叫了過載的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法,我們繼續跟程式碼,如下所示。 ![](https://img-blog.csdnimg.cn/2020090221572392.png#pic_center) 可以看到在過載的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中直接呼叫了registerOrEscalateApcAsRequired()方法。在registerOrEscalateApcAsRequired()方法中,傳入了AnnotationAwareAspectJAutoProxyCreator.class物件。 我們繼續跟進程式碼,如下所示。 ![](https://img-blog.csdnimg.cn/2020090221573396.png) ![](https://img-blog.csdnimg.cn/20200902215743204.png) 我們可以看到,在registerOrEscalateApcAsRequired()方法中,接收到的Class物件的型別為:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator。 在registerOrEscalateApcAsRequired()方法中方法中,首先判斷registry是否包含org.springframework.aop.config.internalAutoProxyCreator型別的bean。如下所示。 ![](https://img-blog.csdnimg.cn/20200902215752520.png) 如果registry中包含org.springframework.aop.config.internalAutoProxyCreator型別的bean,則進行相應的處理,從Spring的原始碼來看,就是將org.springframework.aop.config.internalAutoProxyCreator型別的bean從registry中取出,並且判斷cls物件的name值和apcDefinition的beanClassName值是否相等,如果不相等。則獲取apcDefinition和cls的優先順序,如果apcDefinition的優先順序小於cls的優先順序,則將apcDefinition的beanClassName設定為cls的name值。相對來說,理解起來還是比較簡單的。 我們這裡是第一次執行程式,不會進入到 if 條件中,我們繼續看程式碼,如下所示。 ![](https://img-blog.csdnimg.cn/20200902215803127.png) 這裡,使用RootBeanDefinition來建立一個beanDefinition,並且將org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator的Class物件作為引數傳遞進來。 ![](https://img-blog.csdnimg.cn/20200902215814169.png) 我們繼續往下看程式碼,最終AopConfigUtils類的registerOrEscalateApcAsRequired()方法中,會通過registry呼叫registerBeanDefinition()方法註冊元件,如下所示。 ![](https://img-blog.csdnimg.cn/20200902215823220.png) 並且註冊的bean的名稱為org.springframework.aop.config.internalAutoProxyCreator。 接下來,我們繼續看AspectJAutoProxyRegistrar類的registerBeanDefinitions()原始碼,如下所示。 ![](https://img-blog.csdnimg.cn/2020090221583369.png) 通過AnnotationConfigUtils類的attributesFor方法來獲取@EnableAspectJAutoProxy註解的資訊。接下來,就是判斷proxyTargetClass屬性的值是否為true,如果為true則呼叫AopConfigUtils類的forceAutoProxyCreatorToUseClassProxying()方法;繼續判斷exposeProxy屬性的值是否為true,如果為true則呼叫AopConfigUtils類的forceAutoProxyCreatorToExposeProxy()方法。 **綜上,向Spring的配置類上新增@EnableAspectJAutoProxy註解後,會向IOC容器中註冊AnnotationAwareAspectJAutoProxyCreator。** 接下來,我們來看下AnnotationAwareAspectJAutoProxyCreator類的結構圖。 ![](https://img-blog.csdnimg.cn/20200902215842811.png) 我們簡單梳理下AnnotationAwareAspectJAutoProxyCreato類的核心繼承關係,如下所示。 ```bash AnnotationAwareAspectJAutoProxyCreator --AspectJAwareAdvisorAutoProxyCreator --AbstractAdvisorAutoProxyCreator --AbstractAutoProxyCreator -- ProxyProcessorSupport, SmartInstantiationAwareBeanPostProcessor ``` 檢視繼承關係可以發現,此類實現了Aware與BeanPostProcessor介面,這兩個介面都和Spring bean的初始化有關,由此推測此類主要處理方法都來自這兩個介面的實現方法。同時該類也實現了order方法。 好了,二狗子說:有關AnnotationAwareAspectJAutoProxyCreator類的詳細程式碼和執行流程我們後面再講,他有點消化不了了。 ## 重磅福利 關注「 **冰河技術** 」微信公眾號,後臺回覆 “**設計模式**” 關鍵字領取《**深入淺出Java 23種設計模式**》PDF文件。回覆“**Java8**”關鍵字領取《**Java8新特性教程**》PDF文件。回覆“**限流**”關鍵字獲取《**億級流量下的分散式限流解決方案**》PDF文件,三本PDF均是由冰河原創並整理的超硬核教程,面試必備!! **好了,今天就聊到這兒吧!別忘了點個贊,給個在看和轉發,讓更多的人看到,一起學習,一起進步!!** ## 寫在最後 > 如果你覺得冰河寫的還不錯,請微信搜尋並關注「 **冰河技術** 」微信公眾號,跟冰河學習高併發、分散式、微服務、大資料、網際網路和雲原生技術,「 **冰河技術** 」微信公眾號更新了大量技術專題,每一篇技術文章乾貨滿滿!不少讀者已經通過閱讀「 **冰河技術** 」微信公眾號文章,吊打面試官,成功跳槽到大廠;也有不少讀者實現了技術上的飛躍,成為公司的技術骨幹!如果你也想像他們一樣提升自己的能力,實現技術能力的飛躍,進大廠,升職加薪,那就關注「 **冰河技術** 」微信公眾號吧,每天更新超硬核技術乾貨,讓你對如何提升技術能力不再迷茫! ![](https://img-blog.csdnimg.cn/20200716220443647.png#pic_