代理模式

概述

為其他對(duì)象提供一種代理,用以控制對(duì)這個(gè)對(duì)象對(duì)訪問

分類

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

靜態(tài)代理

image.png
AbstractObject接口
public interface IAbstract {
    public void operation();
}
ProxyObject 代理類,實(shí)現(xiàn)接口

在代理類里面對(duì)被代理類調(diào)用operation()方法前后可以加更多邏輯限制。
例如:在開發(fā)過程中,想要對(duì)原有的方法做改進(jìn),方法一:直接改原來的方法,方法二:調(diào)用代理類,對(duì)產(chǎn)生的結(jié)果進(jìn)行控制,這就是代理模式

//代理類
public class ProxyI implements IAbstract {

    //被代理類對(duì)象
    RealI mRealObject;

    public ProxyI(RealI mRealObject) {
        this.mRealObject = mRealObject;
    }

    @Override
    public void operation() {
        if (mRealObject == null) {
            mRealObject = new RealI();
        }
        //在代理類里面對(duì)被代理類調(diào)用operation()方法前后可以加更多邏輯限制。
        //例如:在開發(fā)過程中,想要對(duì)原有對(duì)方法做改進(jìn),方法一:直接改原來對(duì)方法,方法二:調(diào)用代理類,對(duì)產(chǎn)生對(duì)結(jié)果進(jìn)行控制,這就是代理模式
        mRealObject.operation();
       System.out.println("ProxyI: operation()");

    }
}
被代理類,同樣實(shí)現(xiàn)接口
//被代理類
public class RealI implements IAbstract {

    @Override
    public void operation() {
          System.out.println("RealI: operation()");
    }
}
測(cè)試類
public class ProxyTest {
    public static void main(String[] args) {
        //
        RealI realObject = new RealI();
        ProxyI father = new ProxyI(realObject);
        father.operation();
    }
}

運(yùn)行結(jié)果:


image.png

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

什么是動(dòng)態(tài)代理?
代理類是在程序運(yùn)行時(shí)創(chuàng)建的代理方式,代理類他不是在java代碼中定義的,而是程序運(yùn)行時(shí),根據(jù)我們?cè)趈ava代碼中的配置動(dòng)態(tài)生成的。相比于靜態(tài)代理,他可以很方便的對(duì)代理類的函數(shù)進(jìn)行統(tǒng)一處理,而不用頻繁修改每一個(gè)代理類的函數(shù)(根據(jù)你的業(yè)務(wù)邏輯)

  • 無侵入式擴(kuò)展代碼: 不修改原來對(duì)代碼情況下,增強(qiáng)方法

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

動(dòng)態(tài)代理的實(shí)現(xiàn):

所要實(shí)現(xiàn)的接口

//所要實(shí)現(xiàn)的接口
public interface ISubject {
    void shopping();
}

被代理類

//被代理類
public class Man implements ISubject {
    @Override
    public void shopping() {
        System.out.println("Man :Man Shopping");
    }
}

代理類

//代理類

//動(dòng)態(tài)代理的代理類 必須要實(shí)現(xiàn)InvocationHandler接口,并且每個(gè)代理類的實(shí)例都關(guān)聯(lián)到了一個(gè)handler。
//代理對(duì)象調(diào)用程序的時(shí)候,一定要實(shí)現(xiàn)的接口,
// 當(dāng)通過代理對(duì)象調(diào)用方法的時(shí)候,
// 這個(gè)方法就會(huì)把他指派到InvocationHandler的invoke(Object proxy, Method method, Object[] args)上
public class Proxy implements InvocationHandler {

    private Object target;//要代理的真實(shí)對(duì)象

    public Proxy(Object target) {
        this.target = target;
    }

    //Object proxy:  指代我們所代理的那個(gè)真實(shí)對(duì)象(真實(shí)對(duì)象就是被代理對(duì)象)
    //Method method:  指代的是我們所要調(diào)用真實(shí)對(duì)象的某個(gè)方法的Method對(duì)象
    //Object[] args:   指代的是調(diào)用真實(shí)對(duì)象某個(gè)方法時(shí)接受的所有參數(shù)
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy :" + proxy.getClass().getName());
        System.out.println("proxy :method: " + method);

        //在代理真實(shí)對(duì)象前我們可以添加一些自己的操作
        System.out.println("proxy :在代理真實(shí)對(duì)象前我們可以添加一些自己的操作");

        //當(dāng)代理對(duì)象調(diào)用真實(shí)對(duì)象的方法時(shí),其會(huì)自動(dòng)的跳轉(zhuǎn)到代理對(duì)象關(guān)聯(lián)的handler對(duì)象的invoke方法來進(jìn)行調(diào)用
        method.invoke(target, args);

        //在代理真實(shí)對(duì)象后我們也可以添加一些自己的操作
        System.out.println("proxy :在代理真實(shí)對(duì)象后我們也可以添加一些自己的操作");
        return null;
    }
}

實(shí)現(xiàn)接口方法

public class ProxyTest {
    public static void main(String[] args) {
        //被代理者
        ISubject man = new Man();
        //代理者
        Proxy proxy = new Proxy(man);

        //首先我們解釋一下為什么我們這里可以將其轉(zhuǎn)化為Subject類型的對(duì)象?
        //原因就是在newProxyInstance這個(gè)方法的第二個(gè)參數(shù)上,我們給這個(gè)代理對(duì)象proxy提供了一組什么接口,那么我這個(gè)代理對(duì)象proxy就會(huì)實(shí)現(xiàn)了這組接口,
        //這個(gè)時(shí)候我們當(dāng)然可以將這個(gè)代理對(duì)象強(qiáng)制類型轉(zhuǎn)化為這組接口中的任意一個(gè),因?yàn)檫@里的接口是ISubject類型,所以就可以將其轉(zhuǎn)化為ISubject類型了。
        ISubject subject = (ISubject) java.lang.reflect.Proxy
                .newProxyInstance(man.getClass().getClassLoader(), man.getClass().getInterfaces(), proxy);

        System.out.println("ProxyTest " + subject.getClass().getName());
        //代理對(duì)象調(diào)用接口方法時(shí),會(huì)關(guān)聯(lián)到InvocationHandler到invoke中的方法去執(zhí)行
        subject.shopping();
    }
}

InvocationHandler類源碼

public interface InvocationHandler {
    //Object proxy:  指代我們所代理的那個(gè)真實(shí)對(duì)象(真實(shí)對(duì)象就是被代理對(duì)象)
    //Method method:  指代的是我們所要調(diào)用真實(shí)對(duì)象的某個(gè)方法的Method對(duì)象
    //Object[] args:   指代的是調(diào)用真實(shí)對(duì)象某個(gè)方法時(shí)接受的所有參數(shù)
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
  • 在動(dòng)態(tài)代理中,每個(gè)代理類的對(duì)象都會(huì)關(guān)聯(lián)一個(gè)表示內(nèi)部處理邏輯都InvocationHandler接口的實(shí)現(xiàn),當(dāng)我們調(diào)用了代理對(duì)象所代理的接口中的方法的時(shí)候,這個(gè)方法的調(diào)用就會(huì)被轉(zhuǎn)發(fā)到InvocationHandler這個(gè)接口的 invoke 方法來進(jìn)行調(diào)用。
  • invoke方法的參數(shù)可以獲?。?/li>
  • 所代理的真實(shí)對(duì)象(被代理對(duì)象)、
  • 所要調(diào)用的真實(shí)對(duì)象的方法、
  • 所要調(diào)用的真實(shí)對(duì)象的方法的參數(shù)
  • invoke()返回值返回給我們使用者

newProxyInstance

java.lang.reflect.Proxy作用是動(dòng)態(tài)創(chuàng)建一個(gè)對(duì)象的類,他提供了很多方法我們用的最多的就是 newProxyInstance 這個(gè)方法

 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
            throws IllegalArgumentException {
    Objects.requireNonNull(h);
        final Class<?>[] intfs = interfaces.clone();
 /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);
 try {
 final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
 cons.setAccessible(true);
   }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException | InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
  }
動(dòng)態(tài)代理總結(jié)

調(diào)用java.lang.reflect.Proxy類的newProxyInstanced(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法,他會(huì)根據(jù)我們傳遞來的class對(duì)象,生成一個(gè)代理類,每當(dāng)代理類執(zhí)行接口方法的時(shí)候,就會(huì)調(diào)用InvocationHandler里面的invoke(Object proxy, Method method, Object[] args)方法,在invoke方法中可以執(zhí)行想要的操作,這就是動(dòng)態(tài)代理。
注意??:

  • 代理類他不是在java代碼中手動(dòng)碼的代碼,而是程序運(yùn)行時(shí),根據(jù)我們?cè)趈ava代碼中的配置動(dòng)態(tài)生成的
  • 代理類實(shí)現(xiàn)InvocationHandler接口
  • 反射包中的java.lang.reflect.Proxy類newProxyInstance()創(chuàng)建動(dòng)態(tài)代理
  • 動(dòng)態(tài)代理與靜態(tài)代理最大的不同:動(dòng)態(tài)代理代理類不需要手動(dòng)生成,是運(yùn)行時(shí)候動(dòng)態(tài)生成,根據(jù)我們?cè)趈ava代碼中的配置在運(yùn)行期動(dòng)態(tài)生成的,這個(gè)動(dòng)態(tài)生成的代理類,已經(jīng)實(shí)現(xiàn)了代理中的相關(guān)接口。

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

CGLIB(Code Generation Library)是一個(gè)開源項(xiàng)目!是一個(gè)強(qiáng)大的,高性能,高質(zhì)量的Code生成類庫(kù),它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口。Hibernate用它來實(shí)現(xiàn)PO(Persistent Object 持久化對(duì)象)字節(jié)碼的動(dòng)態(tài)生成。詳解有待更新。

最后編輯于
?著作權(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)容