欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java中動態(tài)代理如何實現(xiàn)詳解

 更新時間:2024年01月26日 09:44:42   作者:蒾酒  
動態(tài)代理是基于接口實現(xiàn)的代理,mybatis就是用這個技術實現(xiàn)的,下面這篇文章主要給大家介紹了關于java中動態(tài)代理如何實現(xiàn)的相關資料,需要的朋友可以參考下

Java實現(xiàn)動態(tài)代理的兩種方式

  • JDK動態(tài)代理:Java.lang.reflect 包中的Proxy類和InvocationHandler接口提供了生成動態(tài)代理類的能力。
  • Cglib動態(tài)代理:Cglib (Code Generation Library )是一個第三方代碼生成類庫,運行時在內(nèi)存中動態(tài)生成一個子類對象從而實現(xiàn)對目標對象功能的擴展。

兩種動態(tài)代理的區(qū)別

JDK 的動態(tài)代理是基于接口的代理。

它要求被代理的類必須實現(xiàn)一個或多個接口。在運行時,JDK 動態(tài)代理會根據(jù)被代理類實現(xiàn)的接口生成一個代理對象,該代理對象實現(xiàn)了被代理類的接口,并將方法的調(diào)用轉發(fā)給真正的被代理類。JDK 動態(tài)代理的優(yōu)點是簡單易用,缺點是只能代理實現(xiàn)了接口的類。

CGLIB 是基于繼承的代理。

它可以代理沒有實現(xiàn)任何接口的類。在運行時,CGLIB 會動態(tài)生成一個被代理類的子類(Cglib包的底層是通過使用一個小而快的字節(jié)碼處理框架ASM,來轉換字節(jié)碼并生成新的類。不鼓勵直接使用ASM,因為它需要你對JVM內(nèi)部結構包括class文件的格式和指令集都很熟悉。),并重寫父類中的方法,從而實現(xiàn)代理功能。CGLIB 的優(yōu)點是可以代理沒有實現(xiàn)接口的類,缺點是生成的代理類需要繼承被代理類,并且無法代理 final 類型的方法。它可以在運行期擴展Java類與實現(xiàn)Java接口。它廣泛的被許多AOP的框架使用,例如Spring AOP和dynaop,為他們提供方法的interception(攔截)。

總結

使用JDK動態(tài)代理的對象必須實現(xiàn)一個或多個接口;而使用cglib代理的對象則無需實現(xiàn)接口,達到代理類無侵入。

JDK 的動態(tài)代理和 CGLIB 都有各自的優(yōu)點和缺點,具體使用哪種方式取決于具體的需求和場景。如果被代理的類已經(jīng)實現(xiàn)了接口,那么可以優(yōu)先考慮使用 JDK 的動態(tài)代理;如果被代理的類沒有實現(xiàn)接口,或者需要對類的所有方法進行代理,那么可以考慮使用 CGLIB。

補充

靜態(tài)代理和動態(tài)代理的區(qū)別

最大的區(qū)別就是靜態(tài)代理是編譯期確定的,但是動態(tài)代理卻是運行期確定的。

同時,使用靜態(tài)代理模式需要程序員手寫很多代碼,這個過程是比較浪費時間和精力的。一旦需要代理的類中方法比較多,或者需要同時代理多個對象的時候,這無疑會增加很大的復雜度。

反射是動態(tài)代理的實現(xiàn)方式之一。

動態(tài)代理的用途

Java的動態(tài)代理,在日常開發(fā)中可能并不經(jīng)常使用,但是并不代表他不重要。Java的動態(tài)代理的最主要的用途就是應用在各種框架中。因為使用動態(tài)代理可以很方便的運行期生成代理類,通過代理類可以做很多事情,比如AOP,比如過濾器、攔截器等。

在我們平時使用的框架中,像servlet的filter、包括spring提供的aop以及struts2的攔截器都使用了動態(tài)代理功能。我們?nèi)粘?吹降膍ybatis分頁插件,以及日志攔截、事務攔截、權限攔截這些幾乎全部由動態(tài)代理的身影。

Spring AOP的實現(xiàn)方式

Spring AOP中的動態(tài)代理主要有兩種方式,JDK動態(tài)代理和CGLIB動態(tài)代理。

JDK動態(tài)代理通過反射來接收被代理的類,并且要求被代理的類必須實現(xiàn)一個接口。JDK動態(tài)代理的核心是InvocationHandler接口和Proxy類。

如果目標類沒有實現(xiàn)接口,那么Spring AOP會選擇使用CGLIB來動態(tài)代理目標類。

CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態(tài)的生成某個類的子類,注意,CGLIB是通過繼承的方式做的動態(tài)代理,因此如果某個類被標記為final,那么它是無法使用CGLIB做動態(tài)代理的。

JDK 動態(tài)代理代碼示例

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        // TODO Auto-generated method stub
        System.out.println("--------------------add----------------------");
    }
}

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         // 在方法調(diào)用前進行性能監(jiān)控
        PerformanceMonior.begin(target.getClass().getName()+"."+method.getName());
       
         // 通過反射調(diào)用目標對象的方法
        Object result = method.invoke(target, args);
       
        // 在方法調(diào)用后結束性能監(jiān)控
        PerformanceMonior.end();
        

        return result;
    }

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

public static void main(String[] args) {
    UserService service = new UserServiceImpl();
    MyInvocationHandler handler = new MyInvocationHandler(service);
    UserService proxy = (UserService) handler.getProxy();
    proxy.add();
}

代碼整體解讀:

說人話就是我們通過jdk的動態(tài)代理,對用戶服務的新增用戶方法,追加了一個性能監(jiān)控功能,通過傳入原對象,得到代理對象(傳入原對象,我攔截開啟性能監(jiān)控功能,我再把方法的調(diào)用轉發(fā)(本質(zhì)就是反射機制調(diào)用)給原對象,原對象方法執(zhí)行結束,我結束性能監(jiān)控)。

Cglib動態(tài)代理代碼示例

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        // TODO Auto-generated method stub
        System.out.println("--------------------add----------------------");
    }
}

public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz) {
        // 設置需要創(chuàng)建子類的類
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        // 通過字節(jié)碼技術動態(tài)創(chuàng)建子類實例
        return enhancer.create();
    }

    // 實現(xiàn)MethodInterceptor接口方法
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
        System.out.println("前置代理");
        // 通過代理類調(diào)用父類中的方法
        Object result = proxy.invokeSuper(obj, args);
        System.out.println("后置代理");
        return result;
    }
}

public class DoCGLib {
    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        // 通過生成子類的方式創(chuàng)建代理類
        UserServiceImpl proxyImp = (UserServiceImpl)proxy.getProxy(UserServiceImpl.class);
        proxyImp.add();
    }
}

總結 

到此這篇關于java中動態(tài)代理如何實現(xiàn)的文章就介紹到這了,更多相關java動態(tài)代理實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論