Spring之AOP流程解析(ProxyFactory)


  本節我們從ProxyFactory開始分析。該類有幾個比較重要的方法——addAdvice、addAdvisor、getProxy,其中最后一個方法是我們本節的重點。前兩個方法都是向ProxyFactory中成員變量advisors中加入成員,以便后面調用方法時實現攔截。
  這里,我們首先來了解前兩個方法。在addAdvice中會調用到addAdvisor,而內部封裝的advisor實際類型是DefaultPointcutAdvisor。如下圖所示,這里將advice封裝到DefaultPointcutAdvisor。這里我們默認只傳入advice參數,在DefaultPointcutAdvisor中的成員變量pointcut默認為Pointcut.TRUE,也就是TruePointcut.INSTANCE,他比較特殊的是通過方法getClassFilter返回的是ClassFilter.TRUE,也就是TrueClassFilter.INSTANCE,通過方法getMethodMatcher返回的是MethodMatcher.TRUE,也就是TrueMethodMatcher.INSTANCE。通過他們的matches方法返回值都是true。接着,在addAdvisor方法中調用了addAdvisorInternal,該方法將入參advisor加入成員變量advisors中,然后將其中的值轉換為數組賦給成員變量advisorArray(該變量用於后來在方法DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice中構建interceptorList列表),然后調用adviceChanged方法將成員變量methodCache中的值清空。
  下面,我們來到本節的重點ProxyFactory.getProxy,該方法並不復雜,只是返回一個代理對象,該代理對象除了實現了ProxyFactory.targetSource.getTargetClass所實現接口,另外實現了SpringProxy、Advised、DecoratingProxy這三個接口。
  在ProxyFactory.getProxy方法中調用了ProxyCreatorSupport.createAopProxy,該方法首先調用了方法activate,然后通過方法getAopProxyFactory獲得成員變量aopProxyFactory,該成員變量在通過ProxyFactory調用時是DefaultAopProxyFactory的實例。關於ProxyCreatorSupport的另一個構造方法,入參為aopProxyFactory,調用是在ProxyFactoryBean.newPrototypeInstance中,我將放在以后來講解。接下來調用了DefaultAopProxyFactory.createAopProxy,這里的入參就是我們的ProxyFactory,這點需要緊記,因為在后來的代理對象調用方法時會用到,這里的入參接着會傳入到接下來構建的AopProxy實現類型中。在DefaultAopProxyFactory.createAopProxy方法中根據情況構造了ObjenesisCglibAopProxy或者JdkDynamicAopProxy。其中JdkDynamicAopProxy是AopProxy基於JDK的實現,而ObjenesisCglibAopProxy是基於Cglib的實現,他直接繼承自CglibAopProxy。這里我只分析JdkDynamicAopProxy,大家有興趣可以看一下ObjenesisCglibAopProxy,二者只是實現方式不同,大體流程是一致的。我們這里然后就調用了JdkDynamicAopProxy.getProxy,這里有一個參數是ClassUtils.getDefaultClassLoader(),該方法獲取的是當前線程的ClassLoader,也就是默認的Launcher$AppClassLoader。然后通過方法AopProxyUtils.completeProxiedInterfaces填充了SpringProxy、Advised、DecoratingProxy這三個接口。而后通過Proxy.newProxyInstance方法構建了代理對象,注意,這里的最后一個入參就是我們這里的JdkDynamicAopProxy。
  下面,假設我們調用了返回的代理對象的某個方法,也就是說,我們將來到JdkDynamicAopProxy.invoke。不知道大家是否還記得,在JdkDynamicAopProxy.advised就是在DefaultAopProxyFactory.createAopProxy方法中的入參,也就是我們的ProxyFactory。讓我們再回到JdkDynamicAopProxy.invoke方法。這里首先獲得了advised.targetSource,也就是ProxyFactory.targetSource。這里的targetSource是在ProxyFactory的構造函數中將入參Object封裝后的TargetSource,默認實現是SingletonTargetSource。接着調用了targetSource.getTarget,也就是獲取到了我們這里的目標對象,也就是構造ProxyFactory時的入參Object。然后,獲取到target的實際類型,調用了advised.getInterceptorsAndDynamicInterceptionAdvice,也就是方法AdvisedSupport.getInterceptorsAndDynamicInterceptionAdvice。該方法根據之前傳入的advisor構建調用鏈。由於我們之前並沒有調用該方法,因此,在AdvisedSupport.methodCache中並沒有該方法的緩存值,然后調用了DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice來構造cached並將其將入到成員變量methodCache中。
  接下來,讓我們來到DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice,該方法實現了將入參config中的Advisors轉換為通過匹配后的MethodInterceptor列表,也就是真實方法調用前的攔截鏈。如下圖所示,這里是getInterceptorsAndDynamicInterceptionAdvice的完整方法。
  1.首先調用GlobalAdvisorAdapterRegistry.getInstance獲得DefaultAdvisorAdapterRegistry。這里我們需要注意的是在DefaultAdvisorAdapterRegistry的構造方法中已經調用registerAdvisorAdapter方法為其成員變量adapters加入了MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter這三個AdvisorAdapter。
  2.調用入參config.getAdvisors獲取在ProxyFactory中配置的advisors。
  3.遍歷ProxyFactory.advisors,一般來說,在ProxyFactory中加入的advisor是DefaultPointcutAdvisor,實現了接口PointcutAdvisor。因此,這里將advisor強轉為PointcutAdvisor,獲取其pointcut,緊接着調用Pointcut.getClassFilter,並調用ClassFilter.matches,判斷目標類型是否與當前pointcut的ClassFilter相匹配,如果返回值為true,則繼續調用PointcutAdvisor.getPointcut.getMethodMatcher獲得MethodMatcher,接着判斷其是否與目標類型的調用方法相匹配。如果當前調用方法確實是攔截點,就會調用DefaultAdvisorAdapterRegistry.getInterceptors將當前advisor轉換為MethodInterceptor列表。
  這里我簡單說一下PointcutAdvisor與Advisor。PointcutAdvisor實現接口Advisor,並且增加了方法getPointcut,返回的Pointcut就是用來判斷當前執行的方法是否與當前PointcutAdvisor相匹配。而advisor的作用就是用來封裝advice,其有一個方法是getAdvice。這里的DefaultAdvisorAdapterRegistry.getInterceptors方法我放到后面來講解。
  4.將返回的MethodInterceptor數組加入到interceptorList中然后返回。
  這里我們首先來到DefaultAdvisorAdapterRegistry.getInterceptors。
  1.如果通過advisor.getAdvice獲取的advice實現了接口MethodInterceptor,則直接將其加入到interceptors列表中。
  2.這里的成員變量adapters就是在DefaultAdvisorAdapterRegistry構造時就填充了MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter。接着遍歷adapters並將滿足條件的advice封裝后加入到interceptors列表中。
  這里我們以MethodBeforeAdviceAdapter為例。在MethodBeforeAdviceAdapter.supportsAdvice方法中僅僅是判斷入參advice是否實現了MethodBeforeAdvice接口,如果滿足條件,則調用MethodBeforeAdviceAdapter.getInterceptor將advice強轉為MethodBeforeAdvice並將其封裝到MethodBeforeAdviceInterceptor中。
  到此為止,我們就構造好了AdviceChain,接下來,來到本節的最后一個重點——構造ReflectiveMethodInvocation,並調用其proceed方法。在構造ReflectiveMethodInvocation時,其最后一個入參就是我們剛剛構造好的chain。接下來,我們來到ReflectiveMethodInvocation.proceed。這里的鏈式調用很類似web應用中的過濾器,可能spirng團隊也是經常寫web架構的。
  1.這里首先判斷當前調用是否已經將所有的調用鏈完成,如果已經完成,則調用invokeJoinpoint,觸發真實要執行的方法。大家可能比較疑惑,這里為什么是interceptorsAndDynamicMethodMatchers.size() - 1,因為這里的currentInterceptorIndex是從-1開始的,如果從0開始的話,那么,顯然就沒有后面的 - 1。
  2.從interceptorsAndDynamicMethodMatchers列表中獲取值,然后調用其invoke方法。這里我把MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor都講解一下。
  如果這里的MethodInterceptor實際類型是MethodInterceptor,那么調用了MethodBeforeAdviceInterceptor.invoke,注意,這里的入參是ReflectiveMethodInvocation,也就是說,這里在調用了advice.before后,接着調用了ReflectiveMethodInvocation.proceed,接着來到ReflectiveMethodInvocation.proceed。
  然后假設這里的MethodInterceptor實際類型是AfterReturningAdviceInterceptor,這里直接就調用了ReflectiveMethodInvocation.proceed,在其調用完成后,調用了advice.afterReturning。
  接着,我們假設這里的MethodInterceptor實際類型是ThrowsAdviceInterceptor,這里直接調用了ReflectiveMethodInvocation.proceed,不過,這里添加了異常捕獲如果獲取到對應的Method,則通過invokeHandlerMethod調用捕獲異常的方法。然后繼續將異常拋出。
  可以說,這里很好的使用的遞歸的思路,實現了攔截器的鏈式調用。
  到這里,本節的內容就結束了。盡管內容洋洋灑灑,但是當你調試代碼的時候,會發現其實並沒有多少東西。希望大家在看本文的時候盡量結合源碼調試,以加深理解。如果有疑問或有相關問題探討,歡迎大家留言。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM