代理模式

什么是代理模式?

被代理對(duì)象的動(dòng)作交由代理對(duì)象執(zhí)行。

代理模式有什么用?

代理模式的初衷是解決不直接調(diào)用目標(biāo)對(duì)象的實(shí)現(xiàn),而是把功能實(shí)現(xiàn)委托給代理對(duì)象對(duì)象的場(chǎng)景。
代理對(duì)象拿到目標(biāo)對(duì)象的實(shí)現(xiàn)后,可以對(duì)邏輯進(jìn)行增強(qiáng),比如像Aop思想,可以在連接點(diǎn)前后增加邏輯。

代理模式有靜態(tài)代理和動(dòng)態(tài)代理兩種,動(dòng)態(tài)代理較為熟知的有jdk和cgLib這兩種。

以下是模仿我們點(diǎn)外賣,外賣小哥幫我們送外賣場(chǎng)景。
1、靜態(tài)代理
定義送外賣行為

public interface Want2Do {
    void getFood();
}

我要去拿外賣

public class OrderPerson implements Want2Do{
    @Override
    public void getFood() {
        System.out.println("要去拿外賣");
    }
}

外賣小哥幫我拿外賣

public class Brother implements Want2Do{
    private Want2Do real;
    public Brother(Want2Do real){
        this.real = real;
    }
    @Override
    public void getFood() {
        real.getFood();
        System.out.println("拿外賣");
    }
}

2、jdk動(dòng)態(tài)代理
我們自己需要去拿外賣

public class Myself implements Want2Do {
    private String name;

    public Myself(String name){
        this.name = name;
    }
    @Override
    public void getFood() {
        System.out.println(name + "正在拿外賣");
    }
}

通過jdk動(dòng)態(tài)代理生成外賣小哥,替我們?nèi)ツ猛赓u

public class Main {
    public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        Object result = Proxy.newProxyInstance(Want2Do.class.getClassLoader(),
                Myself.class.getInterfaces(), new MyInvoke("小王"));
        Want2Do want2Do = (Want2Do) result;
        want2Do.getFood();

    }
}

這個(gè)外賣小哥可以幫很多人送外賣,所以你得告訴他,他幫誰拿外賣

class MyInvoke implements InvocationHandler {

    String name;

    public MyInvoke(String name) {
        this.name = name;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy : " + proxy.getClass());

        System.out.println("method : " + method + " 所屬類 : " + method.getDeclaringClass());
        System.out.println("args : " + args);
        method.invoke(new Myself(name));
        return null;
    }
}

Jdk動(dòng)態(tài)代理大致流程:

1)拿到被代理類的類信息。
2)根據(jù)類信息生成新的Proxy0類信息。
3)將Proxy0類加載到j(luò)vm方法區(qū)中。
4)根據(jù)Proxy0類創(chuàng)建實(shí)例返回。

sun.misc.ProxyGenerator.saveGeneratedFiles設(shè)置為true可以保存代理對(duì)象的類信息

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import designpatten.proxy.jdkProxy.Want2Do;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Want2Do {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void getFood() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("designpatten.proxy.jdkProxy.Want2Do").getMethod("getFood");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

看到這個(gè)代理對(duì)象的類信息,我們可以看到getFood調(diào)用的是外賣小哥的統(tǒng)一方法invoke方法,但是你得告訴他要干嘛,就是傳入的m2。等他拿到外賣你得告訴他送給誰method.invoke(new Myself(name));。

其實(shí)不用理解我送外賣的例子,這個(gè)$Proxy0類的邏輯很清晰,看下就知道怎么調(diào)用的了。

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