代理模式

什么是代理模式?

被代理对象的动作交由代理对象执行。

代理模式有什么用?

代理模式的初衷是解决不直接调用目标对象的实现,而是把功能实现委托给代理对象对象的场景。
代理对象拿到目标对象的实现后,可以对逻辑进行增强,比如像Aop思想,可以在连接点前后增加逻辑。

代理模式有静态代理和动态代理两种,动态代理较为熟知的有jdk和cgLib这两种。

以下是模仿我们点外卖,外卖小哥帮我们送外卖场景。
1、静态代理
定义送外卖行为

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动态代理
我们自己需要去拿外卖

public class Myself implements Want2Do {
    private String name;

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

通过jdk动态代理生成外卖小哥,替我们去拿外卖

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();

    }
}

这个外卖小哥可以帮很多人送外卖,所以你得告诉他,他帮谁拿外卖

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动态代理大致流程:

1)拿到被代理类的类信息。
2)根据类信息生成新的Proxy0类信息。
3)将Proxy0类加载到jvm方法区中。
4)根据Proxy0类创建实例返回。

sun.misc.ProxyGenerator.saveGeneratedFiles设置为true可以保存代理对象的类信息

//
// 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());
        }
    }
}

看到这个代理对象的类信息,我们可以看到getFood调用的是外卖小哥的统一方法invoke方法,但是你得告诉他要干嘛,就是传入的m2。等他拿到外卖你得告诉他送给谁method.invoke(new Myself(name));。

其实不用理解我送外卖的例子,这个$Proxy0类的逻辑很清晰,看下就知道怎么调用的了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容