美文网首页
常用的设计模式(笔记)——代理模式(动态代理)

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

作者: 红鲤鱼与绿鲤鱼与驴与鱼 | 来源:发表于2022-03-18 15:22 被阅读0次

    动态代理

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

    • 静态代理,在程序运行前代理类 (.class)就已经存在了
    • 动态代理,在程序运行时自动生成的代理类(.class)

    静态代理地址: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 ()有三个参数:

    • 被代理对象的ClassLoader
    • 被代理对象实现的接口数组
    • InvocationHandler 调用处理器,指的是被调用对象 的那个 方法被调用的时候 怎么去处理
            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()方法

    相关文章

      网友评论

          本文标题:常用的设计模式(笔记)——代理模式(动态代理)

          本文链接:https://www.haomeiwen.com/subject/zhoidrtx.html