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.
先簡單介紹下這個類的簡單用法:
1:上面ProxyFactory的構造方法,會把傳進去的目标對象封裝成一個TargetSource
2: 還有一種設定目标對象的方式,就是:proxyFactory.setTargetClass(UserService.class);
兩種設定方式得到的 this.targetSource 這個屬性是不一樣的,
一個是: EmptyTargetSource ,一個是 SingletonTargetSource,他們都繼承了 TargetSource,但是對于SingletonTargetSource來說,它的target屬性,和getTargetClass都是可以得到值的。
但是對于EmptyTargetSource 來說,它隻有getTargetClass能得到值,因為是直接指派的,它的getTarget是直接傳回null的。
上面代理工廠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); 查找。
先把原理圖放出來:
上面建立代理類舉例子是通過ProxyFactory來的,在spring中是底層才用到這個類,在spring中有幾種實用的建立AOP代理的方式。
1:通過 BeanNameAutoProxyCreator 這個後置處理器,進行自動代理。
看到它繼承了 AbstractAutoProxyCreator,父類實作了 SmartInstantiationAwareBeanPostProcessor後置處理器,裡面肯定有個postProcessBeforeInstantiation,postProcessAfterInitialization。
在postProcessBeforeInstantiation邏輯中會有判斷是否需要提前建立代理對象的邏輯。還會判斷是否要跳過目前bean的代理邏輯的處理: this.advisedBeans.put(cacheKey, Boolean.FALSE);
一般的AOP代理邏輯處理是在postProcessAfterInitialization中的
1.1:定義 BeanNameAutoProxyCreator
1.2: 定義Advisor
上面的方式配置的AOP邏輯實作了。
2:還有一種通過 DefaultAdvisorAutoProxyCreator來進行AOP邏輯查找比對的方式。
DefaultAdvisorAutoProxyCreator 是找Advisor類型的bean,然後進行比對。就是上面自定義的MyAdvisor。
這個Bean可以替換掉上面的那個BeanNameAutoProxyCreator。但是這種方式也不友善,因為定義Advisor不夠靈活,配置比較麻煩。
3:使用注解,這種方式比較常用。@EnableAspectJAutoProxy
這個注解有 proxyTargetClass 屬性預設false(如果為true表示要使用cglib的動态代理),exposeProxy 屬性預設為false。
Advisor是通過如下方式:
在配置類上加了這個注解之後,這個注解會引入一個類:AspectJAutoProxyRegistrar。和上面的方式相比:
AspectJAutoProxyRegistrar 繼承 ImportBeanDefinitionRegistrar ,具有注冊beanDefinition的功能。就是 registerBeanDefinitions方法:注冊一個AnnotationAwareAspectJAutoProxyCreator 類。
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對象,開頭已經介紹過這個類了。
getProxy中,會先判斷使用JDK代理工廠還是使用cglib的代理工廠
AopProxy有兩種,一種是JdkDynamicAopProxy,一種是CglibAopProxy
JdkDynamicAopProxy#getProxy
不同的Advice對應的不同的類,就是上面說的MethodInterceptor.