java的三種代理

代理

靜態(tài)代理

  1. 編寫需要目標(biāo)對象實(shí)現(xiàn)的接口
/**
 * 接口
 */
public interface Action {

    /**
     * dosomething
     */
    void doSomething();
}
  1. 編寫目標(biāo)類,實(shí)現(xiàn)接口
/**
 * @author earthchen
 * @date 2018/8/10
 **/
public class RealObject implements Action {

    @Override
    public void doSomething() {
        System.out.println(this.getClass().getName()+"dosomething....");
    }
}
  1. 編寫靜態(tài)代理類,也需要實(shí)現(xiàn)該接口
/**
 * 代理類
 *
 * @author earthchen
 * @date 2018/8/10
 **/
public class Proxy implements Action {

    private Action realObject;

    public Proxy(Action realObject) {
        this.realObject = realObject;
    }

    @Override
    public void doSomething() {
        System.out.println("proxy do");
        realObject.doSomething();
    }
}

需要維護(hù)一個(gè)接口的對象

  1. 編寫main方法進(jìn)行測試
public class Main {

    public static void main(String[] args) {
        Action action = new RealObject();
        Proxy proxy = new Proxy(action);
        proxy.doSomething();
    }
}

優(yōu)缺點(diǎn)

這種代理方式需要代理對象和目標(biāo)對象實(shí)現(xiàn)一樣的接口。

  1. 優(yōu)點(diǎn):可以在不修改目標(biāo)對象的前提下擴(kuò)展目標(biāo)對象的功能。

  2. 缺點(diǎn):

  • 冗余。由于代理對象要實(shí)現(xiàn)與目標(biāo)對象一致的接口,會(huì)產(chǎn)生過多的代理類。
  • 不易維護(hù)。一旦接口增加方法,目標(biāo)對象與代理對象都要進(jìn)行修改。

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

  1. 和靜態(tài)代理一樣,編寫一個(gè)接口
/**
 * @author earthchen
 * @date 2018/8/10
 **/
public interface Action {

    void doSomeThing();

}
  1. 編寫多個(gè)目標(biāo)類,實(shí)現(xiàn)接口
/**
 * @author earthchen
 * @date 2018/8/10
 **/
public class RealObject1 implements Action {

    @Override
    public void doSomeThing() {
        System.out.println(this.getClass().getName()+"do someThing...");
    }
}

/**
 * @author earthchen
 * @date 2018/8/10
 **/
public class RealObject2 implements Action {

    @Override
    public void doSomeThing() {
        System.out.println(this.getClass().getName()+"do someThing...");
    }
}
  1. 編寫動(dòng)態(tài)代理類,
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author earthchen
 * @date 2018/8/10
 **/
public class DynamicProxyHandler implements InvocationHandler {

    private Action testAction;

    public DynamicProxyHandler(Action testAction) {
        this.testAction = testAction;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //代理擴(kuò)展邏輯
        System.out.println("proxy do");

        return method.invoke(testAction, args);
    }
}
  1. 編寫main方法進(jìn)行測試
public class Main {

    public static void main(String[] args) {
        RealObject1 realObject1 = new RealObject1();
        Action proxy1 = (Action) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{Action.class}, new DynamicProxyHandler(realObject1));
        proxy1.doSomeThing();


        RealObject2 realObject2 = new RealObject2();
        Action proxy2 = (Action) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{Action.class}, new DynamicProxyHandler(realObject2));
        proxy2.doSomeThing();
    }
}

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

  • 靜態(tài)代理在編譯時(shí)就已經(jīng)實(shí)現(xiàn),編譯完成后代理類是一個(gè)實(shí)際的class文件
  • 動(dòng)態(tài)代理是在運(yùn)行時(shí)動(dòng)態(tài)生成的,即編譯完成后沒有實(shí)際的class文件,而是在運(yùn)行時(shí)動(dòng)態(tài)生成類字節(jié)碼,并加載到JVM中

特點(diǎn):

動(dòng)態(tài)代理對象不需要實(shí)現(xiàn)接口,但是要求目標(biāo)對象必須實(shí)現(xiàn)接口,否則不能使用動(dòng)態(tài)代理。

cglib代理

  1. 在pom.xml中引入cglib的依賴
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.5</version>
</dependency>
  1. 直接編寫需要代理的目標(biāo)類
public class RealObject {

    public void doSomeThing(){
        System.out.println(this.getClass().getName()+"do someThing...");
    }
}
  1. 編寫cglib代理類
import java.lang.reflect.Method;

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

/**
 * @author earthchen
 * @date 2018/8/10
 **/
public class CglibProxy implements MethodInterceptor {

    private Object target;

    public CglibProxy(Object object) {
        this.target = object;
    }

    /**
     * 為目標(biāo)對象生成代理對象
     *
     * @return
     */
    public Object getProxyInstance() {
        //工具類
        Enhancer en = new Enhancer();
        //設(shè)置父類
        en.setSuperclass(target.getClass());
        //設(shè)置回調(diào)函數(shù)
        en.setCallback(this);
        //創(chuàng)建子類對象代理
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before do someThing.....");
        // 執(zhí)行目標(biāo)對象的方法
        Object returnValue = method.invoke(target, objects);
        System.out.println("after do someThing....");
        return returnValue;
    }
}

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

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

cglib特點(diǎn)

  • JDK的動(dòng)態(tài)代理有一個(gè)限制,就是使用動(dòng)態(tài)代理的對象必須實(shí)現(xiàn)一個(gè)或多個(gè)接口。
    如果想代理沒有實(shí)現(xiàn)接口的類,就可以使用CGLIB實(shí)現(xiàn)
  • CGLIB是一個(gè)強(qiáng)大的高性能的代碼生成包,它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口。它廣泛的被許多AOP的框架使用,例如Spring AOP和dynaop,為他們提供方法的interception(攔截)
  • CGLIB包的底層是通過使用一個(gè)小而快的字節(jié)碼處理框架ASM,來轉(zhuǎn)換字節(jié)碼并生成新的類。不鼓勵(lì)直接使用ASM,因?yàn)樗枰銓VM內(nèi)部結(jié)構(gòu)包括class文件的格式和指令集都很熟悉

總結(jié)

  1. 靜態(tài)代理實(shí)現(xiàn)較簡單,只要代理對象對目標(biāo)對象進(jìn)行包裝,即可實(shí)現(xiàn)增強(qiáng)功能,但靜態(tài)代理只能為一個(gè)目標(biāo)對象服務(wù),如果目標(biāo)對象過多,則會(huì)產(chǎn)生很多代理類。
  2. JDK動(dòng)態(tài)代理需要目標(biāo)對象實(shí)現(xiàn)業(yè)務(wù)接口,代理類只需實(shí)現(xiàn)InvocationHandler接口。
  3. 靜態(tài)代理在編譯時(shí)產(chǎn)生class字節(jié)碼文件,可以直接使用,效率高。
  4. 動(dòng)態(tài)代理必須實(shí)現(xiàn)InvocationHandler接口,通過反射代理方法,比較消耗系統(tǒng)性能,但可以減少代理類的數(shù)量,使用更靈活。
  5. cglib代理無需實(shí)現(xiàn)接口,通過生成類字節(jié)碼實(shí)現(xiàn)代理,比反射稍快,不存在性能問題,但cglib會(huì)繼承目標(biāo)對象,需要重寫方法,所以目標(biāo)對象不能為final類。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 代理模式 代理(Proxy)是一種設(shè)計(jì)模式,提供了對目標(biāo)對象另外的訪問方式;即通過代理對象訪問目標(biāo)對象.這樣做的好...
    happyleijun閱讀 1,027評論 0 13
  • Cglib代理 上面的靜態(tài)代理和動(dòng)態(tài)代理模式都是要求目標(biāo)對象是實(shí)現(xiàn)一個(gè)接口的目標(biāo)對象,但是有時(shí)候目標(biāo)對象只是一個(gè)單...
    java部落閱讀 273評論 0 0
  • 1.代理模式 代理(Proxy)是一種設(shè)計(jì)模式,提供了對目標(biāo)對象另外的訪問方式;即通過代理對象訪問目標(biāo)對象.這樣做...
    java部落閱讀 402評論 0 0
  • 《快思慢想》共讀內(nèi)容 1,為什么要共讀這本書? 2,為什么要用共讀的形式? 3,為什么要早晨閱讀? 4,如何推進(jìn)共...
    三片阿司匹林閱讀 557評論 2 3
  • 90天踐行目標(biāo): 目標(biāo) 1. 改善動(dòng)不動(dòng)就打人,生氣就愛扔?xùn)|西的問題,學(xué)會(huì)尊重 目標(biāo) 2. 隨機(jī)問題的記錄與改善 ...
    AmandaGui閱讀 353評論 0 0

友情鏈接更多精彩內(nèi)容