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

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

作者: 红鲤鱼与绿鲤鱼与驴与鱼 | 来源:发表于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()方法

相关文章

  • java动态代理(JDK和cglib)(转载自http://ww

    java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是...

  • 理解代理模式

    原创博客地址 简介 代理模式,也叫做委托模式,分为:静态代理动态代理 代理模式也是平时比较常用的设计模式之一,代理...

  • 大厂高级工程师面试系列:Java动态代理机制和实现原理详解

    代理模式 Java动态代理运用了设计模式中常用的代理模式 代理模式:目的就是为其他对象提供一个代理用来控制对某个真...

  • 设计模式之代理模式

    设计模式之代理模式 10分钟看懂动态代理设计模式(升级篇)-对这篇动态代理模式的思路整理 仿JDK实现动态代理逻辑...

  • java 代理模式详解

    简介 代理是什么? 代理也称“委托”,分为静态代理和动态代理,代理模式也是常用的设计模式之一,具有方法增强、高扩展...

  • 代理模式(Proxy Pattern):动态代理 - 最易懂的设

    前言 今天我来全面总结Android开发中最常用的设计模式 - 代理模式中的动态代理模式 其他设计模式介绍1分钟全...

  • Java 动态代理(1)

    代理模式即Proxy Pattern,23种常用的面向对象软件的设计模式之一。 Java的动态代理比代理的思想更像...

  • Java代理

    代理定义 这是一种常用的设计模式,根据创建代理类的时间点,分为静态代理和动态代理。 代理模式 代理类与委托类有同样...

  • Proxy代理者模式(一)

    摘要 本篇笔记针对Java设计模式中最难理解的代理者模式进行讲解,从静态代理、动态代理,及Java相关代理类的应用...

  • java 动态代理封装使用

    1、java 动态代理原理 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责...

网友评论

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

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