Spring技術(shù)內(nèi)幕(二):AOP(二)


四,Spring AOP攔截器調(diào)用的實現(xiàn)


1. 設(shè)計原理

  1. 在Spring AOP通過JDK的Proxy方式或者CGLIB方式生成代理對象的時候,相關(guān)的攔截器已經(jīng)配置到代理對象中去了。
  2. 設(shè)置攔截器回調(diào)
  • 通過JDK的Proxy方式生成代理對象:通過InvocationHandler設(shè)置攔截器回調(diào)
  • 通過CGLIB方式生成代理對象:根據(jù)CGLIB使用要求,通過DynamicAdvisedInterceptor來完成回調(diào)。

2. JdkDynamicAopProxy的invoke攔截

  • 通過實現(xiàn)InvocationHandler接口中的invoke方法,來完成對目標對象方法調(diào)用的攔截或者說功能增強的工作。
  • 創(chuàng)建ReflectiveMethodInvocation對象來完成對AOP功能實現(xiàn)的封裝
  • invoke方法中對攔截器進行配置的代碼:


    JdkDynamicAopProxy的invoke攔截.png

3. Cglib2AopProxy的intercept攔截

  • 在對于AOP的攔截調(diào)用,回調(diào)在DynamicAdvisedInterceptor對象中實現(xiàn),具體實現(xiàn)是在DynamicAdvisedInterceptor中的intercept方法中
  • 創(chuàng)建CglibMethodInvocation對象來完成攔截器鏈的調(diào)用(JdkDynamicAopProxy通過構(gòu)造ReflectiveMethodInvocation對象來完成這個功能)
  • DynamicAdvisedInterceptor的intercept部分代碼:


    Cglib2AopProxy的intercept攔截.png

4. 目標對象方法的調(diào)用

  • 使用JdkDynamicAopProxy的代理對象:通過AopUtils使用反射機制在AopUtils.invokejoinpointUsingReflection的方法中實現(xiàn)
  • 使用Cglib2AopProxy的代理對象:通過CGLIB的MethodProxy對象直接完成

5. AOP攔截器鏈的調(diào)用

  • 兩種方式對攔截器的調(diào)用都是在ReflectiveMethodInvocation中通過proceed方法實現(xiàn)。在proceed方法中逐個實現(xiàn)攔截器的攔截方法。每個攔截器在執(zhí)行之前,需要對代理方法完成一個匹配判斷(即Pointcut切點中需要進行matches匹配過程)。


    攔截器的運行.png

6. 配置通知器

  1. proceed方法中interceptorOrInterceptionAdvice鏈來自interceptorsAndDynamicMethodMatchers持有的List的一個元素
  2. 而List中的攔截器元素在JDKDynamicAopProxy中的invoke方法或Cglib2AopProxy中DynamicAdvisedInterceptor的intercept回調(diào)中實現(xiàn),并且我們可以從中看出獲取interceptors的操作在advised對象完成。
  3. 這個advised是一個AdvisedSupport對象


    AdvisedSupport取得攔截器.png
  • DefaultAdvisorChainFactory:生成通知器鏈的工廠,實現(xiàn)了interceptor鏈的獲取過程


    DefaultAdvisorChainFactory生成攔截器鏈.png
    • 先設(shè)置一個List,長度為配置的通知器的個數(shù)。該配置即為XML中對ProxyFactory做的interceptNames屬性的配置
    • AdvisorAdapterRegistry:實現(xiàn)攔截器的注冊,對從ProxyFactoryBean配置中得到的同志進行適配,從而獲得相應(yīng)的攔截器
    • 攔截器適配和注冊過程完成以后,List中的攔截器會被JDK生成的AopProxy代理對象的invoke方法或者CGLIB代理對象的intercept攔截方法取得,并啟動攔截器的invoke調(diào)用,最終觸發(fā)通知的切面增強
  1. 在ProxyFactoryBean的getObject方法中對advisor進行初始化


    在攔截器鏈的初始化中獲取advisor通知器.png

    通過對IOC容器的一個getBean回調(diào),得到配置好的advisor通知器

  • 以DefaultListableBeanFactory作為IOC容器時,基類AbstractAutowireCapableBeanFactory有一個對Bean進行初始化的initializeBean方法。在這個方法中,判斷Bean類型是否實現(xiàn)BeanFactoryAware接口


    Bean類型是否實現(xiàn)BeanFactoryAware接口.png
  • 實現(xiàn)一個接口方法setBeanFactory,設(shè)置的this對象表示Bean所在IOC容器,一般指DefaultListableBeanFactory對象。
  • 得到這個設(shè)置好的BeanFactory以后,ProxyFactoryBean就可以通過回調(diào)容器的getBean去獲取配置在Bean定義文件中的通知器,獲取通知器就是向IOC容器回調(diào)getBean(依賴注入)的過程。
  • 在調(diào)用時,ProxyFactoryBean給出通知器的名字,這些名字都是在interceptorNames的List中配置好的,在IOC對FactoryBean進行依賴注入時,會直接注入到FactoryBean的interceptorNames屬性中。完成這個過程后,ProxyFactoryBean就獲得了配置的通知器,為完成切面增強做好了準備。

7. Advice通知的實現(xiàn)

  1. DefaultAdvisorChainFactory(負責(zé)生成攔截器鏈)使用GlobalAdvisorAdapterRegistry得到AOP攔截器
  2. GlobalAdvisorAdapterRegistry的實現(xiàn):單件設(shè)計模式,保證所要生成對象的唯一性


    單件設(shè)計模式.png
  • 配置一個靜態(tài)的final變量instance,使得對象在加載類的時候就生成了
  • 抽象類,不能被實例化,保證instance對象的唯一性
  • 使用instance對象時,通過靜態(tài)方法getInstance方法完成,保證instance唯一對象的獲取
  1. DefaultAdvisorAdapterRegistry設(shè)置了一系列adapter適配器,為Spring AOP的advice提供編織能力。
  2. 以MethodBeforeAdviceAdapter為例,把advice通知從通知器中取出,通過MethodBeforeAdviceInterceptor對象把取得的advice通知包裝起來。在MethodBeforeAdviceInterceptor方法中,會先調(diào)用advice的before方法,在方法調(diào)用之前完成通知增強。

8. ProxyFactory實現(xiàn)AOP

上面的分析著重講解了以ProxyFactoryBean為例Spring AOP的實現(xiàn)原理,除此之外,ProxyFactory也可以實現(xiàn)Spring AOP,而且原理也差不多,只不過后者需要編程式地完成AOP應(yīng)用的設(shè)置。


ProxyFactory.png

參考資料:Spring技術(shù)內(nèi)幕(第2版) 計文柯

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容