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

java中動(dòng)態(tài)代理如何實(shí)現(xiàn)詳解

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

Java實(shí)現(xiàn)動(dòng)態(tài)代理的兩種方式

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

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

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

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

CGLIB 是基于繼承的代理。

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

總結(jié)

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

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

補(bǔ)充

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

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

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

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

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

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

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

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

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

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

如果目標(biāo)類沒有實(shí)現(xiàn)接口,那么Spring AOP會(huì)選擇使用CGLIB來動(dòng)態(tài)代理目標(biāo)類。

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

JDK 動(dòng)態(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)用前進(jìn)行性能監(jiān)控
        PerformanceMonior.begin(target.getClass().getName()+"."+method.getName());
       
         // 通過反射調(diào)用目標(biāo)對(duì)象的方法
        Object result = method.invoke(target, args);
       
        // 在方法調(diào)用后結(jié)束性能監(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的動(dòng)態(tài)代理,對(duì)用戶服務(wù)的新增用戶方法,追加了一個(gè)性能監(jiān)控功能,通過傳入原對(duì)象,得到代理對(duì)象(傳入原對(duì)象,我攔截開啟性能監(jiān)控功能,我再把方法的調(diào)用轉(zhuǎn)發(fā)(本質(zhì)就是反射機(jī)制調(diào)用)給原對(duì)象,原對(duì)象方法執(zhí)行結(jié)束,我結(jié)束性能監(jiān)控)。

Cglib動(dòng)態(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) {
        // 設(shè)置需要?jiǎng)?chuàng)建子類的類
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        // 通過字節(jié)碼技術(shù)動(dòng)態(tài)創(chuàng)建子類實(shí)例
        return enhancer.create();
    }

    // 實(shí)現(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();
    }
}

總結(jié) 

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

相關(guān)文章

最新評(píng)論