CGLib與JDKProxy的區別

来源:http://www.cnblogs.com/resentment/archive/2016/08/05/5742661.html
-Advertisement-
Play Games

Spring AOP 的實現主要有兩種:CGLib與JDK自帶的Proxy。 他們主要的區別是,需要JDKProxy修改的類必須實現介面(因此也只能代理public方法),在創建Proxy時可以使用class.getInterfaces()獲得所有介面併進行代理。 而CGLib不受這個限制可以修改任 ...


Spring AOP 的實現主要有兩種:CGLib與JDK自帶的Proxy。
他們主要的區別是,需要JDKProxy修改的類必須實現介面(因此也只能代理public方法),在創建Proxy時可以使用class.getInterfaces()獲得所有介面併進行代理。
而CGLib不受這個限制可以修改任何非private非final方法。
以上只是一些大家都知道的方面。在這兩種方法的實現中,其實還是有其他一些重要的差別的,那就是調用代理類的方法內部同時調用了自己的另一個方法的話他們的最終結果將是不一樣的,下麵上代碼!

//被代理對象介面
public interface DummyInterface {

    void fun2();

    void fun1();

}
//被代理對象實現
public class Dummy implements DummyInterface {

    public Dummy(){
    }
    public void fun1(){
        System.out.println("fun1 start");
        fun2();    //調用內部方法fun2
        System.out.println("fun1 end");
    }

    public void fun2() {
        System.out.println("-fun2 start");
        System.out.println("-fun2 end");
    }
}
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

//CGLib實現
public class CGlibEnhance implements MethodInterceptor{
    public static void main(String[] args) {
        CGlibEnhance ce = new CGlibEnhance();
        Dummy dummy = (Dummy) ce.getProxy(Dummy.class);//獲得代理對象
        dummy.fun1();
        System.out.println("----");
        dummy.fun2();//直接調用fun2
    }
    
    public Object getProxy(Class<Dummy> clazz) {
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("pre-"+method.getName());  
            Object result = proxy.invokeSuper(obj,args);  
            System.out.println("post-"+method.getName());  
            return result;  
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//JDKProxy實現
public class JavaProxy implements InvocationHandler {
    private Object target;//被代理對象

    public JavaProxy(Object target) {
        super();
        this.target = target;
    }

    public static void main(String[] args) {
        JavaProxy handler = new JavaProxy(new Dummy());

        DummyInterface proxy = (DummyInterface) handler.getProxy();//獲得代理對象
        proxy.fun1();
        System.out.println("----");
        proxy.fun2();//直接調用fun2
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        System.out.println("pre-" + method.getName());
        result = method.invoke(target, args);
        System.out.println("post-" + method.getName());

        return result;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
    }
}

以上兩個方法都代理了Dummy對象並分別調用了fun1 fun2兩個方法,fun1內部又調用了fun2。
兩個結果卻不一樣

//cglib 輸出
pre-fun1
fun1 start
pre-fun2  //★
-fun2 start
-fun2 end 
post-fun2 //★
fun1 end
post-fun1
----
pre-fun2
-fun2 start
-fun2 end
post-fun2
//JDKProxy輸出
pre-fun1
fun1 start
-fun2 start //★
-fun2 end   //★
fun1 end
post-fun1
----
pre-fun2
-fun2 start
-fun2 end
post-fun2

可以看出在fun1調用fun2時(★處),JDKProxy並沒有截獲調用註入pre-fun2/post-fun2,但直接調用fun2時卻接獲到方法調用。
其中原因是CGLib是使用繼承的方式來改寫原類,同時也可以看到在CGLib中我們並沒有手動創建Dummy對象,因為CGLib create方法內部會自動創建。
而JDKProxy正如其名是Proxy,只是對原對象使用了代理模式,無法滲透到方法的內部調用。
這個從側面說明瞭在spring AOP中如果被代理類進行類內部調用時會導致無法註入方法的情況。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 函數指針、回調函數、系統調用區別1.函數指針 2.回調函數 體現: 1.函數名作為參數傳遞給調用函數。 2.將調用者和被調函數分開,回調函數實現具體的功能,調用者無需關註實現的具體細節。3.系統調用系統調用 --> (0x80)軟中斷(系統調用表) --> 內核函數 --> 返回到系統調用層 rea ...
  • 用遞歸的方法實現無限極分類 通常我在寫項目的時候,在寫一些例如商城分類的時候會實現對應分類的上級分類,或者其它項目部門管理的上級部門的時候一般就會用到無限極分類來進行分類 第一步:首先在數據表設計的時候,如果要實現無限極分類,一般我會在數據表多添加一個欄位pid,下麵我通過一張新建的數據表來說明一下 ...
  • php程式是部署在IIS7上面,ajax提交數據時,遇到了兩個問題,一個就是跨域,一個php程式總會被執行兩次。 第一個問題的解決方法,是百度出來的,添加下麵幾行代碼就可以了: header('Access-Control-Allow-Origin:*'); header("Access-Contr ...
  • 虛擬記憶體按頁劃分,我們可以明確告訴系統:某一個虛擬記憶體頁需要和實際記憶體幀相關聯。這樣一來,該記憶體頁就被換進來了,而且不會被系統換出去。這一行為叫做鎖頁(locking a page)。 一般來講頁的換進換出是透明的,一般程式接觸不到這一層。但是呢,鎖頁可以為我們帶來如下好處: 1、速度:如果你的程式 ...
  • 函數的遞歸調用 遞歸的含義 遞歸其實也只是一種演算法上的描述,不是一種新的語法! 有時候,我們解決問題的時候,會遇到這種情況,當我們把一個大的問題按照某種解決方案分成若幹個小的問題的時候,發現這些小問題的解決方案其實和剛纔大問題的解決方案又是一樣的! 典型的,比如:求階乘! 10! = 10 * 9! ...
  • 最近由於公司慢慢往spark方面開始轉型,本人也開始學習,今後陸續會更新一些spark學習的新的體會,希望能夠和大家一起分享和進步。 Spark是什麼? Apache Spark™ is a fast and general engine for large-scale data processin ...
  • 一、總結 二、Bug描述:Mybatis中parameterType使用 mapper層中使用parameterType="java.lang.Integer"基本類型,代碼報錯: 解決辦法,當入參為基本數據類型的使用,使用_parameter代替基本數據類型,如下: 或者在mapper層的介面中, ...
  • 題意概括:那天以後,你好說歹說,都快煉成三寸不爛之舍之際,小A總算不在擺著死人臉,鼓著死魚眼。有了點恢復的徵兆。可孟子這家伙說的話還是有點道理,那什麼天將降....額,總之,由於賢者法陣未完成,而小A又遲遲不現身,FFF團團長連下七道聖火令追殺你們,最先趕到地,機械化部隊,它們除了智能不高外,可以說 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...