天天看點

Spring源碼分析(十)AOP源碼分析

Advice

我們通常都會把他翻譯為通知,其實很不好了解,其實他還有另外一個意思,就是“建議”,我覺得把Advice了解為“建議”會更好。就是代理的邏輯。

比如,我們已經完成了一個功能,這時客戶跟我們說,我建議在這個功能之前可以再增加一些邏輯,再之後再增加一些邏輯。

在Spring中,Advice分為:

前置Advice:MethodBeforeAdvice

後置Advice:AfterReturningAdvice

環繞Advice:MethodInterceptor

異常Advice:ThrowsAdvice

在利用Spring AOP去生成一個代理對象時,我們可以設定這個代理對象的Advice。

而對于Advice來說,它隻表示了“建議”,它沒有表示這個“建議”可以用在哪些方面。

就好比,我們已經完成了一個功能,客戶給這個功能提了一個建議,但是這個建議也許也能用到其他功能上。

這時,就出現了Advisor,表示一個Advice可以應用在哪些地方,而“哪些地方”就是Pointcut(切點)。 

切點,表示我想讓哪些地方加上我的代理邏輯。

比如某個方法,

比如某些方法,

比如某些方法名字首為“find”的方法,

比如某個類下的所有方法,等等。

在Pointcut中,有一個MethodMatcher,表示方法比對器。

 Advisor

 就等于Pointcut+Advice.

Spring源碼分析(十)AOP源碼分析

 先簡單介紹下這個類的簡單用法:

1:上面ProxyFactory的構造方法,會把傳進去的目标對象封裝成一個TargetSource

 2:   還有一種設定目标對象的方式,就是:proxyFactory.setTargetClass(UserService.class);

兩種設定方式得到的  this.targetSource 這個屬性是不一樣的,

一個是: EmptyTargetSource  ,一個是 SingletonTargetSource,他們都繼承了 TargetSource,但是對于SingletonTargetSource來說,它的target屬性,和getTargetClass都是可以得到值的。

Spring源碼分析(十)AOP源碼分析

 但是對于EmptyTargetSource  來說,它隻有getTargetClass能得到值,因為是直接指派的,它的getTarget是直接傳回null的。

Spring源碼分析(十)AOP源碼分析

 上面代理工廠ProxyFactory#getProxy得到一個代理類中,會先得到一個具體的代理工廠,有兩種jdk的代理工廠和cglib的代理工廠。

 DefaultAopProxyFactory#createAopProxy 中:

 而一般在我們使用過程中,如果隻開啟了注解:@EnableAspectJAutoProxy  ,Spring會根據類是否有接口來判斷是否用jdk動态代理還是cglib動态代理。如果在  @EnableAspectJAutoProxy(proxyTargetClass = true) 加上屬性,則就會都優先使用cglib的動态代理。

上面分析了得到代理工廠,代理工廠得到得到代理類是 getProxy()。代理工廠兩個: JdkDynamicAopProxy,ObjenesisCglibAopProxy。

JdkDynamicAopProxy#getProxy()

jdk動态代理生成的代理類是實作一些指定接口的代理類,實作那些接口是: AopProxyUtils.completeProxiedInterfaces(this.advised, true); 查找。

 先把原理圖放出來:

Spring源碼分析(十)AOP源碼分析
Spring源碼分析(十)AOP源碼分析

 上面建立代理類舉例子是通過ProxyFactory來的,在spring中是底層才用到這個類,在spring中有幾種實用的建立AOP代理的方式。

1:通過 BeanNameAutoProxyCreator  這個後置處理器,進行自動代理。

Spring源碼分析(十)AOP源碼分析

看到它繼承了 AbstractAutoProxyCreator,父類實作了 SmartInstantiationAwareBeanPostProcessor後置處理器,裡面肯定有個postProcessBeforeInstantiation,postProcessAfterInitialization。

在postProcessBeforeInstantiation邏輯中會有判斷是否需要提前建立代理對象的邏輯。還會判斷是否要跳過目前bean的代理邏輯的處理: this.advisedBeans.put(cacheKey, Boolean.FALSE);

一般的AOP代理邏輯處理是在postProcessAfterInitialization中的

1.1:定義 BeanNameAutoProxyCreator

1.2: 定義Advisor

Spring源碼分析(十)AOP源碼分析

 上面的方式配置的AOP邏輯實作了。

2:還有一種通過 DefaultAdvisorAutoProxyCreator來進行AOP邏輯查找比對的方式。

 DefaultAdvisorAutoProxyCreator 是找Advisor類型的bean,然後進行比對。就是上面自定義的MyAdvisor。

這個Bean可以替換掉上面的那個BeanNameAutoProxyCreator。但是這種方式也不友善,因為定義Advisor不夠靈活,配置比較麻煩。

Spring源碼分析(十)AOP源碼分析

3:使用注解,這種方式比較常用。@EnableAspectJAutoProxy

這個注解有 proxyTargetClass 屬性預設false(如果為true表示要使用cglib的動态代理),exposeProxy 屬性預設為false。

Spring源碼分析(十)AOP源碼分析

Advisor是通過如下方式:

在配置類上加了這個注解之後,這個注解會引入一個類:AspectJAutoProxyRegistrar。和上面的方式相比:

 AspectJAutoProxyRegistrar  繼承 ImportBeanDefinitionRegistrar ,具有注冊beanDefinition的功能。就是  registerBeanDefinitions方法:注冊一個AnnotationAwareAspectJAutoProxyCreator 類。

Spring源碼分析(十)AOP源碼分析

 AnnotationAwareAspectJAutoProxyCreator 的繼承結構如上圖,它不僅可以找到Advisor類型的bean,還可以找@Aspect标注的bean。

這種注解方式的執行流程按照上面的繼承關系重新整理一下如下:

     是個bean的後置處理器,在某個bean的建立過程中,會執行它裡面的postProcessBeforeInstantiation,postProcessAfterInitialization

 AbstractAutoProxyCreator#postProcessBeforeInstantiation

 上面有兩個方法isInfrastructureClass,shouldSkip可以由子類來判斷一個bean要不要進行代理。

AnnotationAwareAspectJAutoProxyCreator #isInfrastructureClass

父類中AbstractAutoProxyCreator#isInfrastructureClass

 AspectJAwareAdvisorAutoProxyCreator#shouldSkip

父類中AbstractAutoProxyCreator#shouldSkip

在 AspectJAwareAdvisorAutoProxyCreator#shouldSkip中有一個 findCandidateAdvisors 的方法,找到所有候選者Advisor

它由子類重寫了,AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors如下

假如上面執行個體化之前的那個方法沒有進行Aop代理,那麼正常AOP代理對象是在postProcessAfterInitialization中産生的。

AbstractAutoProxyCreator#postProcessAfterInitialization

 首先建立ProxyFactory對象,開頭已經介紹過這個類了。

Spring源碼分析(十)AOP源碼分析

 getProxy中,會先判斷使用JDK代理工廠還是使用cglib的代理工廠

AopProxy有兩種,一種是JdkDynamicAopProxy,一種是CglibAopProxy

JdkDynamicAopProxy#getProxy

 不同的Advice對應的不同的類,就是上面說的MethodInterceptor.

Spring源碼分析(十)AOP源碼分析