1. 程式人生 > >Spring AOP 實現過程的總結

Spring AOP 實現過程的總結


      根據bean物件的資訊,從工廠中查詢匹配的一個或多個通知Advisor物件,工廠通過Advisor.class型別查詢到所有的Advisor型別,然後使用bean的class型別與Advisor對應的目標型別匹配,匹配成功的就取得該通知物件形成集合,幷包裝成Advisor介面物件集合。
   
      AdvisedSupport從使用者定義的資訊中取得包含了所有關於目標物件的資訊和設定,還包括通知器攔截器等,這個物件是生成AOP代理方法的輸入引數。代理工廠ProxyFactory繼承了AdvisedSupport擁有了代理需要的配置,呼叫getProxy方法來得到代理物件Object。getProxy方法實現是根據bean的資訊不同進行不同的代理方式:JDK代理或CGLIB代理。

      JDK代理物件和CGLIB代理物件,如果沒有設定指定代理目標類,AOP自動識別進行代理,目標物件是介面類則使用JDK代理,否則就使用CGLIB代理。

      JDK中所要進行動態代理的類必須要實現一個介面,也就是說只能對該類所實現介面中定義的方法進行代理,這在實際程式設計中具有一定的侷限性,而且使用反射的效率也並不是很高.
  使用CGLib實現動態代理,完全不受代理類必須實現介面的限制,而且CGLib底層採用ASM位元組碼生成框架,使用位元組碼技術生成代理類,反射效率要高。唯一需要注意的是,CGLib不能對宣告為final的方法進行代理,因為CGLib原理是動態生成被代理類的子類。

    JDK代理三要素Proxy.newProxyInstance(類載入器,目標介面,InvocationHandler實現),JDKDynaimicAopProxy實現了InvocationHandler介面,並使用了AdvisedSupport中存在的目標介面,及設定的類載入器,進行JDK的動態代理。

    CGLIB建立代理主要是建立Enhancer enhancer,並通過AdvisedSupport設定相應的屬性,比如目標類rootClass,如果由介面合併介面給代理類,最主要的是設定Callback集合和CallbackFilter,使用CallBackFilter可以根據方法的不同使用不同的Callback進行攔截和增強方法。其中最主要的使用於AOP的Callback是DynamicAdvisedInterceptor。

    代理完成後,在從IOC容器中訪問該物件時,返回的將是一個代理物件。當呼叫該物件的方法時,則根據不同的代理,呼叫的代理方法也不同。

    使用JDK動態代理的回撥方法是
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

     使用CGLIB代理物件的回撥方法是
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable

        通過一系列的準備,已經為實現AOP的橫切機奠定了基礎,在這個基礎上,AOP的Advisor已經可以通過AOPProxy代理物件的攔截機制,對需要它進行增強的target目標物件發揮切面的強大威力。

       可以把AOP的實現部分堪稱有基礎設施準備和AOP執行輔助這兩部分組成,這裡的AOPProxy代理物件的生成,可以看作是一個靜態的AOP基礎設施的建立過程。通過這個準備過程,把代理物件、攔截器這些待呼叫的部分都準備好,等待著AOP執行過程中對這些基礎設施的使用。對於應用觸發的AOP應用,會涉及AOP框架的執行和對AOP基礎設施的使用。這些動態的執行部分,是從攔截器回撥入口開始的。

      攔截器回撥入口在JDK的invoke方法和CGLIB的 intercept方法中,當代理物件的方法被呼叫時,會觸發相應的invoke方法或intercept方法,根據目標物件查詢相應的攔截器鏈,如果不存在攔截器鏈直接呼叫目標物件的方法。否則就開始攔截器鏈的呼叫。JDK代理和CGLIB最終會殊途同歸,它們對攔截器鏈的呼叫都是在ReflectiveMethodInvocation類中通過proceed方法實現的。ReflectiveMethodInvocation類實現了AOP 聯盟定義方法攔截介面MethodInvocation,其中該介面中proceed()方法會逐個執行攔截器的攔截方法。ponitCut動態方法匹配成功的攔截器則進行方法的呼叫,這裡使用了責任鏈的模式,主要程式碼這段interceptor.invoke(this);

      想一想自行車上的鏈子,一節鏈子連線另一節鏈子,當一節鏈子被齒輪帶動,則這節鏈子會帶動另一節鏈子。invoken方法是齒輪,interceptor和this都是MethodInterceptor的例項,相當於this是當前一節鏈,interceptor是後一節鏈,齒輪轉動時,後一節鏈條需要當前的鏈條帶動。就像當於interceptor.invoke(this); 而這裡是攔截器鏈,是一個集合。相當於有多個的鏈條連線著。這樣一鏈呼叫另一鏈迴圈著直到鏈條結束,當然現實的鏈條不能斷,不然自行車就沒法騎了。

      這些鏈條是如何形成的呢? 鏈條裡是包含什麼?invoke方法裡處理什麼呢?
        一個攔截器鏈需要實現MethodInterceptor介面,並實現Object invoke(MethodInvocation invocation)方法,在invoke方法中,如果需要下一個鏈條或得到前一個鏈條結果,則需要呼叫方法引數MethodInvocation的proceed()方法,進行下一個鏈條,預設進入ReflectiveMethodInvocation進行處理。

      Spring定義三個MethodInterceptor實現,分別為MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor
分別為目標方法呼叫前進行前置通知攔截器,目標方法呼叫後進行後置通知攔截器,及目標物件出現異常進行異常通知攔截器,在方法invoke中,會呼叫通知的方法,通知的方法是使用者定義的業務邏輯。因此MethodInterceptor需要通知物件Advisor,從Advisor中取得通知Advice。不同的方法攔截器需要的不同的通知物件,後置攔截器需要後置通知,前置攔截器需要前置通知,而異常攔截器需要異常通知,這裡就需要把通知適配成攔截器。

       這些通知存在AdvisedSupport中,從AdvisedSupport物件中取得所有Advisor,Spring使用了介面卡模式,取得這些Advisor包含的通知物件,根據通知物件的型別,適配成相應的攔截器,適配完的攔截器就形成了攔截器鏈。

      當ReflectiveMethodInvocation中interceptor.invoke(this);就會進行攔截器鏈的呼叫,呼叫的實際是通知方法即使用者的業務邏輯,呼叫的前後根據invoke()方法中,業務邏輯在呼叫proceed()方法前還是後來決定。


下面引用:Spring技術內幕--深入解析Spring架構與設計原理

      在Spring的平臺功能中,AOP是一個核心模組,通過對AOP的使用,極大地豐富了Spring框架地功能,比如在各種驅動元件的實現上,很靈活地運用了AOP的功能特性。
      在Spring AOP的基礎實現中,可以瞭解Spring如何得到AOPProxy代理物件,一即如何利用AOPProxy代理物件來對攔截器進行處理。Proxy代理物件的使用,在SpringAOP的實現過程中是非常重要的一個部分,Spring AOP充分利用了像Java的Proxy、反射技術以及第三方位元組碼技術實現CGLIB這些技術方案,通過這些技術,完成了AOP需要的AopProxy代理物件的生成。回顧通過ProxyFactoryBean實現AOP的整個過程,可以看到,在它的實現中,首先需要對目標物件以及攔截器進行正確配置,以便AopProxy代理物件順利產生;這些配置既可以通過配置ProxyFactoryBean的屬性來完成,也可以通過程式設計式地使用ProxyFactory來實現,這兩種AOP地使用方式只是在表面配置地方式上不同,對於內在地AOP實現原理它們是一樣地。在生成AopProxy代理物件地時候,Spring AOP設計了專門的AopProxyFactory作為AopProxy代理物件的生產工廠,由它來負責產生相應的AopProxy代理物件,在使用ProxyFactoryBean得到AopProxy代理物件的時候,預設使用的AopProxy代理物件的生產工廠是DefaultAopProxyFactory物件。這個物件是AopProxy生產過程中一個比較重要的類,它定義了AopProxy代理物件的生成策略,從而決定使用那種AopProxy代理物件的生成技術(是使用JDK的動態代理還是CGLIB)來完成生產任務。而最終的AOPProxy代理物件的產生,則交給了JdkDynamicAopProxy和Cglib2AopProxy這兩個具體的工廠來完成,它們使用了不同的生產技術。

      在得到AopProxy代理物件後,在代理的介面方法被呼叫執行的時候,也就是當AopProxy暴露代理的方法被呼叫的時候,前面定義的Proxy機制就起作用了。當Proxy物件暴露的方法被呼叫時,並不是直接執行目標物件的呼叫方法,而是根據Proxy的定義,改變原有的目標物件方法呼叫的執行軌跡。這種改變體現在,首先會觸發對這些方法呼叫進行攔截,這些攔截為目標呼叫的功能增強提供了工作空間。攔截過程在JDK的Proxy代理物件中,是通過invoke方法來完成的,這個invoke方法是虛擬機器觸發的一個回撥;而在CGLIB的Proxy代理物件中,攔截是由設定好的回撥callback方法來完成。有了這些攔截器的攔截作用,才會有AOP切面增強大顯身手的舞臺。