<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    歡迎光臨郝學(xué)武的blog。

    Spring AOP講解

    Posted on 2012-06-12 18:56 陜西BOY 閱讀(352) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): java基礎(chǔ)知識(shí)點(diǎn)
    Spring AOP使用動(dòng)態(tài)代理技術(shù)在運(yùn)行期織入增強(qiáng)的代碼,為了揭示Spring AOP底層的工作機(jī)理,有必要對(duì)涉及到的Java知識(shí)進(jìn)行學(xué)習(xí)。Spring AOP使用了兩種代理機(jī)制:一種是基于JDK的動(dòng)態(tài)代理;另一種是基于CGLib的動(dòng)態(tài)代理。之所以需要兩種代理機(jī)制,很大程度上是因?yàn)镴DK本身只提供接口的代理,而不支持類(lèi)的代理。

    帶有橫切邏輯的實(shí)例

    我們通過(guò)具體化代碼實(shí)現(xiàn)上一節(jié)所介紹例子的性能監(jiān)視橫切邏輯,并通過(guò)動(dòng)態(tài)代理技術(shù)對(duì)此進(jìn)行改造。在調(diào)用每一個(gè)目標(biāo)類(lèi)方法時(shí)啟動(dòng)方法的性能監(jiān)視,在目標(biāo)類(lèi)方法調(diào)用完成時(shí)記錄方法的花費(fèi)時(shí)間。

    代碼清單6-2  ForumService:包含性能監(jiān)視橫切代碼
    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.baobaotao.proxy;   
    2. public class ForumServiceImpl implements ForumService {   
    3.     public void removeTopic(int topicId) {   
    4.                
    5.          //①-1開(kāi)始對(duì)該方法進(jìn)行性能監(jiān)視   
    6.         PerformanceMonitor.begin(   
    7.                             "com.baobaotao.proxy.ForumServiceImpl. removeTopic");   
    8.         System.out.println("模擬刪除Topic記錄:"+topicId);   
    9.         try {   
    10.             Thread.currentThread().sleep(20);   
    11.         } catch (Exception e) {   
    12.             throw new RuntimeException(e);   
    13.         }          
    14.   
    15.          //①-2結(jié)束對(duì)該方法進(jìn)行性能監(jiān)視   
    16.         PerformanceMonitor.end();   
    17.     }   
    18.   
    19.     public void removeForum(int forumId) {   
    20.           //②-1開(kāi)始對(duì)該方法進(jìn)行性能監(jiān)視   
    21.         PerformanceMonitor.begin(   
    22. "com.baobaotao.proxy.ForumServiceImpl. removeForum");   
    23.         System.out.println("模擬刪除Forum記錄:"+forumId);   
    24.         try {   
    25.             Thread.currentThread().sleep(40);   
    26.         } catch (Exception e) {   
    27.             throw new RuntimeException(e);   
    28.         }          
    29.   
    30.          //②-2結(jié)束對(duì)該方法進(jìn)行性能監(jiān)視   
    31.         PerformanceMonitor.end();   
    32.     }   
    33. }  

    代碼清單6-2中粗體表示的代碼就是具有橫切邏輯特征的代碼,每個(gè)Service類(lèi)和每個(gè)業(yè)務(wù)方法體的前后都執(zhí)行相同的代碼邏輯:方法調(diào)用前啟動(dòng)PerformanceMonitor,方法調(diào)用后通知PerformanceMonitor結(jié)束性能監(jiān)視并給記錄性能監(jiān)視結(jié)果。

    PerformanceMonitor是性能監(jiān)視的實(shí)現(xiàn)類(lèi),我們給出一個(gè)非常簡(jiǎn)單的實(shí)現(xiàn)版本,其代碼如代碼清單6-3所示:

    代碼清單6-3  PerformanceMonitor
    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.baobaotao.proxy;   
    2. public class PerformanceMonitor {   
    3.      //①通過(guò)一個(gè)ThreadLocal保存調(diào)用線程相關(guān)的性能監(jiān)視信息   
    4.     private static ThreadLocal<MethodPerformace> performanceRecord =           
    5.                                 new ThreadLocal<MethodPerformance>();   
    6.        
    7.     //②啟動(dòng)對(duì)某一目標(biāo)方法的性能監(jiān)視   
    8.      public static void begin(String method) {   
    9.         System.out.println("begin monitor...");   
    10.         MethodPerformance mp = new MethodPerformance(method);   
    11.         performanceRecord.set(mp);   
    12.     }   
    13.     public static void end() {   
    14.         System.out.println("end monitor...");   
    15.         MethodPerformance mp = performanceRecord.get();   
    16.   
    17.          //③打印出方法性能監(jiān)視的結(jié)果信息。   
    18.         mp.printPerformance();   
    19.     }   
    20. }  

    ThreadLocal是將非線程安全類(lèi)改造為線程安全類(lèi)的法寶,在9.2節(jié)中我們將詳細(xì)介紹這個(gè)Java基礎(chǔ)知識(shí)。PerformanceMonitor提供了兩個(gè)方法:通過(guò)調(diào)用begin(String method)方法開(kāi)始對(duì)某個(gè)目標(biāo)類(lèi)方法的監(jiān)視,method為目標(biāo)類(lèi)方法的全限定名;而end()方法結(jié)束對(duì)目標(biāo)類(lèi)方法的監(jiān)視,并給出性能監(jiān)視的信息。這兩個(gè)方法必須配套使用。

    用于記錄性能監(jiān)視信息的MethodPerformance類(lèi)的代碼如所示:

    代碼清單6-4  MethodPerformance
    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.baobaotao.proxy;   
    2. public class MethodPerformance {   
    3.     private long begin;   
    4.     private long end;   
    5.     private String serviceMethod;   
    6.     public MethodPerformance(String serviceMethod){   
    7.        this.serviceMethod = serviceMethod;   
    8.   
    9.        //①記錄目標(biāo)類(lèi)方法開(kāi)始執(zhí)行點(diǎn)的系統(tǒng)時(shí)間     
    10.        this.begin = System.currentTimeMillis();    
    11.     
    12.     }   
    13.     public void printPerformance(){   
    14.         
    15.         //②獲取目標(biāo)類(lèi)方法執(zhí)行完成后的系統(tǒng)時(shí)間,并進(jìn)而計(jì)算出目標(biāo)類(lèi)方法執(zhí)行時(shí)間   
    16.         end = System.currentTimeMillis();    
    17.         long elapse = end - begin;   
    18.     
    19.         //③報(bào)告目標(biāo)類(lèi)方法的執(zhí)行時(shí)間   
    20.         System.out.println(serviceMethod+"花費(fèi)"+elapse+"毫秒。");     
    21.     }   
    22. }  

    通過(guò)下面的代碼測(cè)試擁有性能監(jiān)視能力的ForumServiceImpl業(yè)務(wù)方法:

    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.baobaotao.proxy;   
    2.   
    3. public class TestForumService {   
    4.     public static void main(String[] args) {   
    5.         ForumService forumService = new ForumServiceImpl();   
    6.         forumService .removeForum(10);   
    7.        forumService .removeTopic(1012);   
    8.     }   
    9. }  

    我們得到以下輸出信息:
    引用
    begin monitor... ①removeForum(10)方法的性能監(jiān)視報(bào)告
    模擬刪除Forum記錄:10
    end monitor...
    com.baobaotao.proxy.ForumServiceImpl.removeForum花費(fèi)47毫秒。

    begin monitor... ①removeTopic(1012)方法的性能監(jiān)視報(bào)告
    模擬刪除Topic記錄:1012
    end monitor...
    com.baobaotao.proxy.ForumServiceImpl.removeTopic花費(fèi)26毫秒。

    正如代碼清單6 2實(shí)例所示,當(dāng)某個(gè)方法需要進(jìn)行性能監(jiān)視,就必須調(diào)整方法代碼,在方法體前后分別添加上開(kāi)啟性能監(jiān)視和結(jié)束性能監(jiān)視的代碼。這些非業(yè)務(wù)邏輯的性能監(jiān)視代碼破壞了ForumServiceImpl業(yè)務(wù)邏輯的純粹性。我們希望通過(guò)代理的方式,將業(yè)務(wù)類(lèi)方法中開(kāi)啟和結(jié)束性能監(jiān)視的這些橫切代碼從業(yè)務(wù)類(lèi)中完全移除。并通過(guò)JDK動(dòng)態(tài)代理技術(shù)或CGLib動(dòng)態(tài)代理技術(shù)將橫切代碼動(dòng)態(tài)織入到目標(biāo)方法的相應(yīng)位置。

    JDK動(dòng)態(tài)代理

    JDK 1.3以后,Java提供了動(dòng)態(tài)代理的技術(shù),允許開(kāi)發(fā)者在運(yùn)行期創(chuàng)建接口的代理實(shí)例。在Sun剛推出動(dòng)態(tài)代理時(shí),還很難想象它有多大的實(shí)際用途,現(xiàn)在我們終于發(fā)現(xiàn)動(dòng)態(tài)代理是實(shí)現(xiàn)AOP的絕好底層技術(shù)。

    JDK的動(dòng)態(tài)代理主要涉及到j(luò)ava.lang.reflect包中的兩個(gè)類(lèi):Proxy和InvocationHandler。其中InvocationHandler是一個(gè)接口,可以通過(guò)實(shí)現(xiàn)該接口定義橫切邏輯,并通過(guò)反射機(jī)制調(diào)用目標(biāo)類(lèi)的代碼,動(dòng)態(tài)將橫切邏輯和業(yè)務(wù)邏輯編織在一起。

    而Proxy利用InvocationHandler動(dòng)態(tài)創(chuàng)建一個(gè)符合某一接口的實(shí)例,生成目標(biāo)類(lèi)的代理對(duì)象。這樣講一定很抽象,我們馬上著手使用Proxy和InvocationHandler這兩個(gè)魔法戒對(duì)上一節(jié)中的性能監(jiān)視代碼進(jìn)行革新。

    首先,我們從業(yè)務(wù)類(lèi)ForumServiceImpl中刪除性能監(jiān)視的橫切代碼,使ForumServiceImpl只負(fù)責(zé)具體的業(yè)務(wù)邏輯,如代碼清單6-5所示:

    代碼清單6-5  ForumServiceImpl:移除性能監(jiān)視橫切代碼
    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.baobaotao.proxy;   
    2.   
    3. public class ForumServiceImpl implements ForumService {   
    4.   
    5.     public void removeTopic(int topicId) {   
    6.                                 ①   
    7.         System.out.println("模擬刪除Topic記錄:"+topicId);   
    8.         try {   
    9.             Thread.currentThread().sleep(20);   
    10.         } catch (Exception e) {   
    11.             throw new RuntimeException(e);   
    12.         }   
    13.                               ①   
    14.     }   
    15.     public void removeForum(int forumId) {   
    16.                           ②   
    17.         System.out.println("模擬刪除Forum記錄:"+forumId);   
    18.         try {   
    19.             Thread.currentThread().sleep(40);   
    20.         } catch (Exception e) {   
    21.             throw new RuntimeException(e);   
    22.         }   
    23.                           ②   
    24.     }   
    25. }  

    在代碼清單6-5中的①和②處,原來(lái)的性能監(jiān)視代碼被移除了,我們只保留了真正的業(yè)務(wù)邏輯。

    從業(yè)務(wù)類(lèi)中移除的性能監(jiān)視橫切代碼當(dāng)然不能漂浮在空氣中,它還得找到一個(gè)安身之所,InvocationHandler就是橫切代碼的安家樂(lè)園,我們將性能監(jiān)視的代碼安置在PerformanceHandler中,如代碼清單6-6所示:

    Java代碼 復(fù)制代碼 收藏代碼
    1. 代碼清單6-6  PerformanceHandler   
    2. package com.baobaotao.proxy;   
    3. import java.lang.reflect.InvocationHandler;   
    4. import java.lang.reflect.Method;   
    5.   
    6. public class PerformanceHandler implements InvocationHandler {//①實(shí)現(xiàn)InvocationHandler   
    7.     private Object target;   
    8.     public PerformanceHandler(Object target){ //②target為目標(biāo)的業(yè)務(wù)類(lèi)   
    9.         this.target = target;   
    10.     }   
    11.     public Object invoke(Object proxy, Method method, Object[] args) ③   
    12.             throws Throwable {   
    13.         PerformanceMonitor.begin(target.getClass().getName()+"."+ method. getName());③-1  
    14.         Object obj = method.invoke(target, args);// ③-2通過(guò)反射方法調(diào)用業(yè)務(wù)類(lèi)的目標(biāo)方法   
    15.         PerformanceMonitor.end();③-1  
    16.         return obj;   
    17.     }   
    18. }  


    ③處invoke()方法中粗體所示部分的代碼為性能監(jiān)視的橫切代碼,我們發(fā)現(xiàn),橫切代碼只出現(xiàn)一次,而不是原來(lái)那樣星灑各處。③-2處的method.invoke()語(yǔ)句通過(guò)Java反射機(jī)制間接調(diào)用目標(biāo)對(duì)象的方法,這樣InvocationHandler的invoke()方法就將橫切邏輯代碼(③-1)和業(yè)務(wù)類(lèi)方法的業(yè)務(wù)邏輯代碼(③-2)編織到一起了,所以我們可以將InvocationHandler看成是一個(gè)編織器。下面,我們對(duì)這段代碼做進(jìn)一步的說(shuō)明。

    首先,我們實(shí)現(xiàn)InvocationHandler接口,該接口定義了一個(gè) invoke(Object proxy, Method method, Object[] args)的方法,proxy是最終生成的代理實(shí)例,一般不會(huì)用到;method是被代理目標(biāo)實(shí)例的某個(gè)具體方法,通過(guò)它可以發(fā)起目標(biāo)實(shí)例方法的反射調(diào)用;args是通過(guò)被代理實(shí)例某一個(gè)方法的入?yún)ⅲ诜椒ǚ瓷湔{(diào)用時(shí)使用。

    此外,我們?cè)跇?gòu)造函數(shù)里通過(guò)target傳入希望被代理的目標(biāo)對(duì)象,如②處所示,在InvocationHandler接口方法invoke(Object proxy, Method method, Object[] args)里,將目標(biāo)實(shí)例傳給method.invoke()方法,調(diào)用目標(biāo)實(shí)例的方法,如③所示。
    下面,我們通過(guò)Proxy結(jié)合PerformanceHandler創(chuàng)建ForumService接口的代理實(shí)例,如代碼清單6-7所示:

    代碼清單6-7  TestForumService:創(chuàng)建代理實(shí)例
    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.baobaotao.proxy;   
    2. import java.lang.reflect.Proxy;   
    3. public class TestForumService {   
    4.     public static void main(String[] args) {   
    5.                   
    6.                //①希望被代理的目標(biāo)業(yè)務(wù)類(lèi)   
    7.         ForumService target = new ForumServiceImpl();    
    8.            
    9.                //②將目標(biāo)業(yè)務(wù)類(lèi)和橫切代碼編織到一起   
    10.         PerformanceHandler handler = new PerformanceHandler(target);   
    11.            
    12.                 //③根據(jù)編織了目標(biāo)業(yè)務(wù)類(lèi)邏輯和性能監(jiān)視橫切邏輯的InvocationHandler實(shí)例創(chuàng)建代理實(shí)例   
    13.         ForumService proxy = (ForumService) Proxy.newProxyInstance(     
    14.                 target.getClass().getClassLoader(),   
    15.                 target.getClass().getInterfaces(),   
    16.                 handler);   
    17.   
    18.                 //④調(diào)用代理實(shí)例   
    19.         proxy.removeForum(10);      
    20.         proxy.removeTopic(1012);   
    21.     }   
    22. }  

    上面的代碼完成業(yè)務(wù)類(lèi)代碼和橫切代碼的編織工作并生成了代理實(shí)例。在②處,我們讓PerformanceHandler將性能監(jiān)視橫切邏輯編織到ForumService實(shí)例中,然后在③處,通過(guò)Proxy的newProxyInstance()靜態(tài)方法為編織了業(yè)務(wù)類(lèi)邏輯和性能監(jiān)視邏輯的handler創(chuàng)建一個(gè)符合ForumService接口的代理實(shí)例。該方法的第一個(gè)入?yún)轭?lèi)加載器;第二個(gè)入?yún)閯?chuàng)建代理實(shí)例所需要實(shí)現(xiàn)的一組接口;第三個(gè)參數(shù)是整合了業(yè)務(wù)邏輯和橫切邏輯的編織器對(duì)象。

    按照③處的設(shè)置方式,這個(gè)代理實(shí)例實(shí)現(xiàn)了目標(biāo)業(yè)務(wù)類(lèi)的所有接口,即Forum ServiceImpl的ForumService接口。這樣,我們就可以按照調(diào)用ForumService接口實(shí)例相同的方式調(diào)用代理實(shí)例,如④所示。運(yùn)行以上的代碼,輸出以下信息:
    引用
    begin monitor...
    模擬刪除Forum記錄:10
    end monitor...
    com.baobaotao.proxy.ForumServiceImpl.removeForum花費(fèi)47毫秒。

    begin monitor...
    模擬刪除Topic記錄:1012
    end monitor...
    com.baobaotao.proxy.ForumServiceImpl.removeTopic花費(fèi)26毫秒。

    我們發(fā)現(xiàn),程序的運(yùn)行效果和直接在業(yè)務(wù)類(lèi)中編寫(xiě)性能監(jiān)視邏輯的效果一致,但是在這里,原來(lái)分散的橫切邏輯代碼已經(jīng)被我們抽取到PerformanceHandler中。當(dāng)其他業(yè)務(wù)類(lèi)(如UserService、SystemService等)的業(yè)務(wù)方法也需要使用性能監(jiān)視時(shí),我們只要按照代碼清單6-7相似的方式,分別為它們創(chuàng)建代理對(duì)象就可以了。下面,我們通過(guò)時(shí)序圖描述通過(guò)創(chuàng)建代理對(duì)象進(jìn)行業(yè)務(wù)方法調(diào)用的整體邏輯,以進(jìn)一步認(rèn)識(shí)代理對(duì)象的本質(zhì),如圖6-3所示。





    我們?cè)谏蠄D中使用虛線的方式對(duì)通過(guò)Proxy創(chuàng)建的ForumService代理實(shí)例加以凸顯,F(xiàn)orumService代理實(shí)例內(nèi)部利用PerformaceHandler整合橫切邏輯和業(yè)務(wù)邏輯。調(diào)用者調(diào)用代理對(duì)象的removeForum()和removeTopic()方法時(shí),上圖的內(nèi)部調(diào)用時(shí)序清晰地告訴我們實(shí)際上所發(fā)生的一切。

    CGLib動(dòng)態(tài)代理

    使用JDK創(chuàng)建代理有一個(gè)限制,即它只能為接口創(chuàng)建代理實(shí)例,這一點(diǎn)我們可從Proxy的接口newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)的方法簽名中就看得很清楚:第二個(gè)入?yún)nterfaces就是需要代理實(shí)例實(shí)現(xiàn)的接口列表。雖然面向接口編程的思想被很多大師級(jí)人物(包括Rod Johnson)推崇,但在實(shí)際開(kāi)發(fā)中,許多開(kāi)發(fā)者也對(duì)此深感困惑:難道對(duì)一個(gè)簡(jiǎn)單業(yè)務(wù)表的操作也需要老老實(shí)實(shí)地創(chuàng)建5個(gè)類(lèi)(領(lǐng)域?qū)ο箢?lèi)、Dao接口,Dao實(shí)現(xiàn)類(lèi),Service接口和Service實(shí)現(xiàn)類(lèi))嗎?難道不能直接通過(guò)實(shí)現(xiàn)類(lèi)構(gòu)建程序嗎?對(duì)于這個(gè)問(wèn)題,我們很難給出一個(gè)孰好孰劣的準(zhǔn)確判斷,但我們確實(shí)發(fā)現(xiàn)有很多不使用接口的項(xiàng)目也取得了非常好的效果(包括大家所熟悉的SpringSide開(kāi)源項(xiàng)目)。

    對(duì)于沒(méi)有通過(guò)接口定義業(yè)務(wù)方法的類(lèi),如何動(dòng)態(tài)創(chuàng)建代理實(shí)例呢?JDK的代理技術(shù)顯然已經(jīng)黔驢技窮,CGLib作為一個(gè)替代者,填補(bǔ)了這個(gè)空缺。

    CGLib采用非常底層的字節(jié)碼技術(shù),可以為一個(gè)類(lèi)創(chuàng)建子類(lèi),并在子類(lèi)中采用方法攔截的技術(shù)攔截所有父類(lèi)方法的調(diào)用,并順勢(shì)織入橫切邏輯。下面,我們采用CGLib技術(shù),編寫(xiě)一個(gè)可以為任何類(lèi)創(chuàng)建織入性能監(jiān)視橫切邏輯代理對(duì)象的代理創(chuàng)建器,如代碼清單 6-8所示:

    代碼清單6-8  CglibProxy
    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.baobaotao.proxy;   
    2. import java.lang.reflect.Method;   
    3. import net.sf.cglib.proxy.Enhancer;   
    4. import net.sf.cglib.proxy.MethodInterceptor;   
    5. import net.sf.cglib.proxy.MethodProxy;   
    6.   
    7. public class CglibProxy implements MethodInterceptor {   
    8.     private Enhancer enhancer = new Enhancer();   
    9.     public Object getProxy(Class clazz) {   
    10.         enhancer.setSuperclass(clazz); //① 設(shè)置需要?jiǎng)?chuàng)建子類(lèi)的類(lèi)   
    11.         enhancer.setCallback(this);    
    12.         return enhancer.create(); //②通過(guò)字節(jié)碼技術(shù)動(dòng)態(tài)創(chuàng)建子類(lèi)實(shí)例   
    13.     
    14.     }   
    15.   
    16.         //③攔截父類(lèi)所有方法的調(diào)用   
    17.     public Object intercept(Object obj, Method method, Object[] args,    
    18.             MethodProxy proxy) throws Throwable {   
    19.         PerformanceMonitor.begin(obj.getClass().getName()+"."+method. getName());//③-1   
    20.         Object result=proxy.invokeSuper(obj, args); ③-2    
    21.         PerformanceMonitor.end();//③-1通過(guò)代理類(lèi)調(diào)用父類(lèi)中的方法   
    22.         return result;   
    23.     }   
    24. }  

    在上面代碼中,用戶(hù)可以通過(guò)getProxy(Class clazz)為一個(gè)類(lèi)創(chuàng)建動(dòng)態(tài)代理對(duì)象,該代理對(duì)象通過(guò)擴(kuò)展clazz創(chuàng)建代理對(duì)象。在這個(gè)代理對(duì)象中,我們織入性能監(jiān)視的橫切邏輯(③-1)。intercept(Object obj, Method method, Object[] args,MethodProxy proxy)是CGLib定義的Interceptor接口的方法,它攔截所有目標(biāo)類(lèi)方法的調(diào)用,obj表示目標(biāo)類(lèi)的實(shí)例;method為目標(biāo)類(lèi)方法的反射對(duì)象;args為方法的動(dòng)態(tài)入?yún)ⅲ欢鴓roxy為代理類(lèi)實(shí)例。

    下面,我們通過(guò)CglibProxy為ForumServiceImpl類(lèi)創(chuàng)建代理對(duì)象,并測(cè)試代理對(duì)象的方法,如代碼清單6-9所示:

    代碼清單6-9  TestForumService:測(cè)試Cglib創(chuàng)建的代理類(lèi)
    Java代碼 復(fù)制代碼 收藏代碼
    1. package com.baobaotao.proxy;   
    2. import java.lang.reflect.Proxy;   
    3. public class TestForumService {   
    4.     public static void main(String[] args) {   
    5.       CglibProxy proxy = new CglibProxy();   
    6.       ForumServiceImpl forumService = ①    
    7.                 (ForumServiceImpl )proxy.getProxy(ForumServiceImpl.class);   
    8.       forumService.removeForum(10);   
    9.       forumService.removeTopic(1023);   
    10.     }   
    11. }  


    在①中,我們通過(guò)CglibProxy為ForumServiceImpl動(dòng)態(tài)創(chuàng)建了一個(gè)織入性能監(jiān)視邏輯的代理對(duì)象,并調(diào)用代理類(lèi)的業(yè)務(wù)方法。運(yùn)行上面的代碼,輸入以下信息:
    引用
    begin monitor...
    模擬刪除Forum記錄:10
    end monitor...
    com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0.removeForum花費(fèi)47毫秒。
    begin monitor...
    模擬刪除Topic記錄:1023
    end monitor...
    com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0.removeTopic花費(fèi)16毫秒。

    觀察以上的輸出,除了發(fā)現(xiàn)兩個(gè)業(yè)務(wù)方法中都織入了性能監(jiān)控的邏輯外,我們還發(fā)現(xiàn)代理類(lèi)的名字是com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0,這個(gè)特殊的類(lèi)就是CGLib為ForumServiceImpl動(dòng)態(tài)創(chuàng)建的子類(lèi)。

    代理知識(shí)小結(jié)

    Spring AOP的底層就是通過(guò)使用JDK動(dòng)態(tài)代理或CGLib動(dòng)態(tài)代理技術(shù)為目標(biāo)Bean織入橫切邏輯。在這里,我們對(duì)前面兩節(jié)動(dòng)態(tài)創(chuàng)建代理對(duì)象作一個(gè)小結(jié)。

    我們雖然通過(guò)PerformanceHandler或CglibProxy實(shí)現(xiàn)了性能監(jiān)視橫切邏輯的動(dòng)態(tài)織入,但這種實(shí)現(xiàn)方式存在三個(gè)明顯需要改進(jìn)的地方:

    1)目標(biāo)類(lèi)的所有方法都添加了性能監(jiān)視橫切邏輯,而有時(shí),這并不是我們所期望的,我們可能只希望對(duì)業(yè)務(wù)類(lèi)中的某些特定方法添加橫切邏輯;
    2)我們通過(guò)硬編碼的方式指定了織入橫切邏輯的織入點(diǎn),即在目標(biāo)類(lèi)業(yè)務(wù)方法的開(kāi)始和結(jié)束前織入代碼;
    3)我們手工編寫(xiě)代理實(shí)例的創(chuàng)建過(guò)程,為不同類(lèi)創(chuàng)建代理時(shí),需要分別編寫(xiě)相應(yīng)的創(chuàng)建代碼,無(wú)法做到通用。

    以上三個(gè)問(wèn)題,在AOP中占用重要的地位,因?yàn)镾pring AOP的主要工作就是圍繞以上三點(diǎn)展開(kāi):Spring AOP通過(guò)Pointcut(切點(diǎn))指定在哪些類(lèi)的哪些方法上織入橫切邏輯,通過(guò)Advice(增強(qiáng))描述橫切邏輯和方法的具體織入點(diǎn)(方法前、方法后、方法的兩端等)。此外,Spring通過(guò)Advisor(切面)將Pointcut和Advice兩者組裝起來(lái)。有了Advisor的信息,Spring就可以利用JDK或CGLib的動(dòng)態(tài)代理技術(shù)采用統(tǒng)一的方式為目標(biāo)Bean創(chuàng)建織入切面的代理對(duì)象了。

    只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     

    posts - 17, comments - 65, trackbacks - 0, articles - 28

    Copyright © 陜西BOY

    主站蜘蛛池模板: 99久久精品国产免费| 亚洲国产精品无码久久九九大片 | 免费观看成人久久网免费观看| 香蕉国产在线观看免费| 国产精品亚洲va在线观看| 久久久久亚洲精品无码网址色欲 | 久久久久亚洲AV片无码| 久久久久亚洲AV成人无码网站| 亚洲V无码一区二区三区四区观看| 亚洲人成人无码网www电影首页| 亚洲男同帅GAY片在线观看| 亚洲无人区午夜福利码高清完整版 | 日本道免费精品一区二区| 亚洲黄片手机免费观看| 中文字幕不卡免费高清视频| 两个人www免费高清视频| 日本免费中文字幕| 7x7x7x免费在线观看| 西西大胆无码视频免费| 麻豆国产VA免费精品高清在线 | 麻豆国产精品入口免费观看| 免费在线观看你懂的| 亚洲最大av无码网址| 亚洲国产精品一区第二页| 亚洲色图校园春色| 国产成人精品日本亚洲专区6| 亚洲精品无码成人片久久不卡 | 亚洲欧洲精品国产区| 亚洲综合一区国产精品| 精品在线免费视频| a毛片在线免费观看| 精品一区二区三区免费毛片爱 | 国产一级a毛一级a看免费人娇| 高清一区二区三区免费视频| 日日麻批免费40分钟日本的| 日韩成人免费在线| 久久亚洲中文字幕精品一区| 亚洲精品第一国产综合精品| 在线观看亚洲免费| 男女作爱在线播放免费网站| 日韩欧美一区二区三区免费观看|