Java代理設(shè)計(jì)模式(Proxy)的幾種具體實(shí)現(xiàn)

Proxy是一種結(jié)構(gòu)設(shè)計(jì)模型,主要解決對(duì)象直接訪問(wèn)帶來(lái)的問(wèn)題,代理又分為靜態(tài)代理和動(dòng)態(tài)代理(JDK代理、CGLIB代理。
靜態(tài)代理:又程序創(chuàng)建的代理類,或者特定的工具類,在平時(shí)開發(fā)中經(jīng)常用到這種代理模式,這種一般在程序運(yùn)行前就已經(jīng)生成對(duì)應(yīng)的class文件;
動(dòng)態(tài)代理:在程序運(yùn)行時(shí)通過(guò)反射機(jī)制動(dòng)態(tài)創(chuàng)建。

下面通過(guò)一個(gè)場(chǎng)景實(shí)現(xiàn)以下三種代理方式

  • 步驟一:定義商店接口(Subject)
  • 步驟二:個(gè)人店家運(yùn)營(yíng)(RealSubject)
  • 步驟三:平臺(tái)運(yùn)營(yíng)(proxy)
  • 步驟四:個(gè)體消費(fèi)(client)


幾種代理方式都會(huì)用到Subject、RealSubject,現(xiàn)在這里定義
Store.java(Subject):定義兩個(gè)接口operate(運(yùn)營(yíng)),business(交易)。

public interface Store {
    /**
     * 店鋪運(yùn)營(yíng)
     */
    public void operate();

    /**
     * 店鋪交易
     */
    public void business();
}

PersonStore.java(RealSubject) 單個(gè)用戶運(yùn)營(yíng)

public class PersonStore implements Store {
    @Override
    public void operate() {
        System.out.println("個(gè)人商店運(yùn)營(yíng)");
    }

    @Override
    public void business() {
        System.out.println("個(gè)人商店交易");
    }
}

靜態(tài)代理

靜態(tài)代理的實(shí)現(xiàn)比較簡(jiǎn)單,代理類通過(guò)實(shí)現(xiàn)與目標(biāo)對(duì)象相同的接口,并在類中維護(hù)一個(gè)代理對(duì)象,這種場(chǎng)景用于個(gè)體商家比較少的情況,如果多的話代理類十分繁多、不易維護(hù)

創(chuàng)建靜態(tài)代理類

ProxyStroe.java(proxy):在代理平臺(tái)運(yùn)營(yíng)是收取管理費(fèi)用100,這個(gè)代理類需要實(shí)現(xiàn)Store接口,并制定目標(biāo)類target(PersonStore)。

public class ProxyStroe implements Store{

    private Store personStore = new PersonStore();

    @Override
    public void operate() {
        System.out.println("收取管理費(fèi)用100元");
        personStore.operate();
    }

    @Override
    public void business() {
        personStore.business();
    }
}

靜態(tài)代理調(diào)用

StaticConsumer.java(client):通過(guò)創(chuàng)建ProxyStroe去代理PersonStore,并進(jìn)行操作。

public class StaticConsumer {

    public static void main(String[] args) {
        ProxyStroe store = new ProxyStroe();
        store.operate();
        store.business();
    }
}

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

JDK代理

動(dòng)態(tài)代理類是通過(guò)接口實(shí)現(xiàn)的,利用攔截器(攔截器必須實(shí)現(xiàn)InvocationHanlder)加上反射機(jī)制生成一個(gè)實(shí)現(xiàn)代理接口的匿名類,
在調(diào)用具體方法前調(diào)用InvokeHandler來(lái)處理。

創(chuàng)建jdk代理類

JDKStoreHandler.java(proxy):通過(guò)實(shí)現(xiàn)InvocationHandler接口的invoke方法,在里面進(jìn)行反射調(diào)用,newProxyInstanse通過(guò)目標(biāo)對(duì)象創(chuàng)建真是對(duì)象。

public class JDKStoreHandler implements InvocationHandler {

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if("operate".equals(method.getName())){
            System.out.println("收取管理費(fèi)用100元");
        }
        return method.invoke(targetObject, args);
    }

    /**
     *
     * @param targetObject
     * @return
     */
    public Object newProxyInstanse(Object targetObject){
        this.targetObject = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
    }
}

JDK代理對(duì)象調(diào)用

JDKDynamicConsumer.java(proxy):通過(guò)JDKStoreHandler的newProxyInstanse創(chuàng)建真實(shí)目標(biāo)對(duì)象,并調(diào)用接口的方法

public class JDKDynamicConsumer {

    public static void main(String[] args) {
        Store store = (Store)new JDKStoreHandler().newProxyInstanse(new PersonStore());
        store.operate();
        store.business();
    }
}

CGLIB代理

cglib動(dòng)態(tài)代理是利用asm開源包,對(duì)代理對(duì)象類的class文件加載進(jìn)來(lái),通過(guò)修改其字節(jié)碼生成子類來(lái)處理。

創(chuàng)建cglib代理對(duì)象

CglibProxy.java(proxy):需要實(shí)現(xiàn)MethodInterceptor的intercept方法,并進(jìn)行反射調(diào)用。通過(guò)createProxyObject創(chuàng)建真實(shí)對(duì)象,這里是根據(jù)目標(biāo)對(duì)象直接生成對(duì)象。

public class CglibProxy implements MethodInterceptor{

    /**
     * CGlib需要代理的目標(biāo)對(duì)象
     */
    private Object targetObject;

    public Object createProxyObject(Object targetObject){
        this.targetObject = targetObject;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetObject.getClass());
        enhancer.setCallback(this);
        Object proxyObj = enhancer.create();
        return proxyObj;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if("operate".equals(method.getName())){
            System.out.println("收取管理費(fèi)用100元");
        }
        return method.invoke(targetObject, objects);
    }
}

CGLib代理對(duì)象調(diào)用

CglibDynamicConsumer.java(client):通過(guò)CglibProxy的createProxyObject創(chuàng)建真實(shí)目標(biāo)對(duì)象,對(duì)進(jìn)行方法調(diào)用

public class CglibDynamicConsumer {

    public static void main(String[] args) {
        Store store = (Store)new CglibProxy().createProxyObject(new PersonStore());
        store.operate();
        store.business();
    }
}

源碼已上傳:https://github.com/itrickzhang/proxy-demo

本文由博客一文多發(fā)平臺(tái) OpenWrite 發(fā)布!

?著作權(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ù)。

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

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