常用的设计模式(笔记)——代理模式(动态代理)

2022-03-18  本文已影响0人  红鲤鱼与绿鲤鱼与驴与鱼

动态代理

动态代理与静态代理的区别:

静态代理地址:https://www.jianshu.com/p/75b3847cca5a

我们需要代理的东西多了,比如“卖烟”、“卖酒”、“卖房子”,每一个需要被代理的的对象都需要对应一个代理者,这样肯定是不太友好的,所以才有了动态代理
动态代理需要java.lang.reflect包下的 Proxy
还是需要一个接口

/**
 * 售卖接口
 */
public interface SellInterface {
    void sell();
}

被代理类

/**
 * 奔驰品牌,被代理的对象
 */
public class BMwBrand implements SellInterface {
    @Override
    public void sell() {
        System.out.println("奔驰卖出了一件商品");
    }
}

动态代理:如下
Proxy.newProxyInstance ()有三个参数:

        BMWBrand brand = new BMWBrand();
        SellInterface sellInterface = (SellInterface) Proxy.newProxyInstance(BMWBrand.class.getClassLoader(),
              new Class[]{SellInterface.class}, 
              new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("销售员拿提成");
                Object obj = method.invoke(brand, args);
                System.out.println("销售员提成");
                return obj;
            }
        });
        sellInterface.sell();

输出:
销售员加价
奔驰卖出了一件商品
销售员拿提成

代码都能看懂,但是为什么 sellInterface.sell()会调用到InvocationHandler的invoke方法?

想要了解这个需要加入下面这一行代码,jdk 版本低添加第一个,版本高就添加第二个

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
或者
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

加入之后会生成 $Proxy0.class,这个class就是动态生成的代理类

截屏2022-03-19 下午2.53.58.png

$Proxy0.class代码如下

public final class $Proxy0 extends Proxy implements SellInterface {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    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 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 void sell() throws  {
        try {
            super.h.invoke(this, m3, (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"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("proxy.study_02.SellInterface").getMethod("sell");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

可以看到这个Class文件继承了Proxy并实现了我们的SellInterface,所以当我们调sellInterface.sell();时就是调用的$Proxy0.class 中的sell() 方法
我们可以按住ctrl点击一下$Proxy0中的sell()这个方法,就会跳转到我们调用的地方

SellInterface sellInterface = (SellInterface) Proxy.newProxyInstance(bmwBrand.getClass().getClassLoader(), new Class[]{SellInterface.class}, new MyInvocationHandler(bmwBrand));
sellInterface.sell(); //当我们调用这一行代码时其实就是调用的 $Proxy0.class 中的sell() 方法

再来看一下 代理类 中的 sell() 方法

image.png
这里的sell方法是调用了父类(Proxy)中成员变量hinvoke方法
image.png

这个h是哪来的呢,就是我的调用Proxy.newProxyInstance()方法时传入的第三个参数InvocationHandler,所以就会调用到他的invoke()方法

上一篇 下一篇

猜你喜欢

热点阅读