Java靜態(tài)代理與動(dòng)態(tài)代理

前言

最近在學(xué)習(xí)設(shè)計(jì)模式,個(gè)人覺得代理模式比較重要,就在網(wǎng)上找了很多代理模式相關(guān)的知識(shí)點(diǎn),總結(jié)如下,希望可以幫到有需要的小伙伴 :)

一、代理模式

  1. 定義:代理模式,顧名思義就是提供一個(gè)代理類,可以訪問原對(duì)象并且替原對(duì)象進(jìn)行一些操作。
  2. 優(yōu)點(diǎn):使用代理模式可以在保證不修改原有類的同時(shí)(即滿足對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉的原則),對(duì)原有類增加一些功能實(shí)現(xiàn)。

二、靜態(tài)代理

  1. 定義:靜態(tài)代理就是在編譯時(shí)就確定了代理類與被代理類的關(guān)系。

  2. 實(shí)現(xiàn)思路:定義一個(gè)接口 Subject,定義一個(gè)目標(biāo)類 RealSubject 和一個(gè)代理類 ProxySubject同時(shí)實(shí)現(xiàn) Subject 這個(gè)接口,在代理類 ProxySubject中持有目標(biāo)類RealSubject對(duì)象,并對(duì)目標(biāo)類RealSubject對(duì)象的方法進(jìn)行一些增強(qiáng)實(shí)現(xiàn)。代碼如下:

  3. Subject 接口

public interface Subject {
    public void doSomething();
}
  1. 目標(biāo)類 RealSubject
/**
 * 目標(biāo)類
 *
 * @Author Marshal
 * @Date 2019-05-20 23:09
 */
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("This is RealSubject~s method!");
    }
}
  1. 代理類 ProxySubject
/**
 *  代理類
 *
 * @Author Marshal
 * @Date 2019-05-20 23:09
 */
public class ProxySubject implements Subject {

    // 持有目標(biāo)對(duì)象
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void doSomething() {
        // 在被代理對(duì)象的方法前后增加業(yè)務(wù)
        before();
        realSubject.doSomething();
        after();
    }

    private void after() {
        System.out.println("after proxy");
    }

    private void before() {
        System.out.println("before proxy");
    }
}

  1. 測(cè)試類
public class ProxyTest {
    public static void main(String[] args) {
        Subject subject = new ProxySubject(new RealSubject());
        subject.doSomething();
    }
}
  1. 輸出結(jié)果如下:
before proxy
This is RealSubject~s method!
after proxy
總結(jié)
  1. 優(yōu)點(diǎn):
  • 代理模式在客戶端與目標(biāo)對(duì)象之間起到一個(gè)中介作用和保護(hù)目標(biāo)對(duì)象的作用
  • 代理對(duì)象可以擴(kuò)展目標(biāo)對(duì)象的功能
  • 代理模式能將客戶端與目標(biāo)對(duì)象分離,在一定程度上降低了系統(tǒng)的耦合度
  1. 缺點(diǎn):
  • 因?yàn)榇韺?duì)象需要與目標(biāo)對(duì)象實(shí)現(xiàn)一樣的接口,所以會(huì)有很多代理類,類太多.同時(shí),一旦接口增加方法,目標(biāo)對(duì)象與代理對(duì)象都要維護(hù)

PS: 靜態(tài)代理的缺點(diǎn),可以通過動(dòng)態(tài)代理來解決。

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

  1. 定義 :代理類在程序運(yùn)行時(shí)創(chuàng)建的代理方式被稱為動(dòng)態(tài)代理。也就是說,代理類并不需要在Java代碼中定義,而是在運(yùn)行時(shí)動(dòng)態(tài)生成的。相比于靜態(tài)代理,動(dòng)態(tài)代理的優(yōu)勢(shì)在于可以很方便的對(duì)代理類的函數(shù)進(jìn)行統(tǒng)一的處理,而不用修改每個(gè)代理類的函數(shù)。
  2. Java的動(dòng)態(tài)代理主要有兩種,即JDK代理和Cglib代理

3.1 JDK代理

使用JDK動(dòng)態(tài)代理有一個(gè)很大的限制,就是它要求目標(biāo)類必須實(shí)現(xiàn)了對(duì)應(yīng)方法的接口,它只能為接口創(chuàng)建代理實(shí)例。
我們繼續(xù)接著使用上面的類,JDK代理類需要實(shí)現(xiàn)InvocationHandler接口,通過實(shí)現(xiàn)該接口定義橫切邏輯,并通過反射機(jī)制調(diào)用目標(biāo)類的代碼,動(dòng)態(tài)的將橫切邏輯和業(yè)務(wù)邏輯編織在一起。代碼如下:

  1. JDKProxyjdk代理類:
/**
 *  動(dòng)態(tài)代理之JDK代理
 *
 * @Author Marshal
 * @Date 2019-05-20 23:15
 */
public class JDKProxy implements InvocationHandler {

    // 目標(biāo)對(duì)象
    private Object object;

    public JDKProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----------JDKProxy before------------");
        Object invoke = method.invoke(object, args);
        System.out.println("-----------JDKProxy after------------");
        return invoke;
    }
}

  1. 測(cè)試類:
/**
 * @Author Marshal
 * @Date 2019-05-21 21:39
 */
public class JDKProxyTest {

    public static void main(String[] args) {

        // 被代理的類
        RealSubject realSubject = new RealSubject();
        // 代理類
        JDKProxy jdkProxy = new JDKProxy(realSubject);
        // 生成代理對(duì)象
        Subject subject = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), new Class[]{Subject.class}, jdkProxy);

        subject.doSomething();
    }
}

  1. 測(cè)試
-----------JDKProxy before------------
This is RealSubject~s method!
-----------JDKProxy after------------

3.2 cglib代理

使用cglib實(shí)現(xiàn)動(dòng)態(tài)代理,并不要求委托類必須實(shí)現(xiàn)接口,底層采用asm字節(jié)碼生成框架生成代理類的字節(jié)碼,我們需要導(dǎo)入 cglib-nodep-3.2.6.jar 包。實(shí)現(xiàn)步驟如下:

  1. 新建一個(gè)目標(biāo)類CglibRealSubject
public class CglibRealSubject {

    public void doSomething() {
        System.out.println("This is CglibRealSubject~s method!");
    }
}
  1. 代理類CglibProxy實(shí)現(xiàn)MethodInterceptor接口并重寫intercept方法
/**
 *  Cglib代理
 *  cglib-nodep-3.2.6.jar : https://github.com/cglib/cglib/releases/tag/RELEASE_3_2_6
 *
 * @Author Marshal
 * @Date 2019-05-22 21:23
 */
public class CglibProxy implements MethodInterceptor {


    public Object getProxyInstance(Class cla) {
        // 1. 工具類
        Enhancer en = new Enhancer();
        // 2. 設(shè)置父類
        en.setSuperclass(cla);
        // 3. 設(shè)置回調(diào)函數(shù)
        en.setCallback(this);
        // 4. 創(chuàng)建子類(代理對(duì)象)
        return en.create();
    }

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy)
            throws Throwable {
        System.out.println("-------------Before CglibProxy-------------");
        // 目標(biāo)方法調(diào)用
        Object invoke = methodProxy.invokeSuper(object, args);
        System.out.println("-------------After CglibProxy-------------");
        return invoke;
    }
}
  1. 測(cè)試
public class CglibProxyTest {
    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        CglibRealSubject realSubject = (CglibRealSubject) proxy.getProxyInstance(CglibRealSubject.class);
        realSubject.doSomething();
    }
}

  1. 輸出結(jié)果
-------------Before CglibProxy-------------
This is CglibRealSubject~s method!
-------------After CglibProxy-------------

3.3 動(dòng)態(tài)代理的應(yīng)用

動(dòng)態(tài)代理主要運(yùn)用于框架中,例如在Spring的AOP中:

  1. 如果加入容器的目標(biāo)對(duì)象有實(shí)現(xiàn)接口,使用JDK代理
  2. 如果目標(biāo)對(duì)象沒有實(shí)現(xiàn)接口,則使用Cglib代理
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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