zoukankan      html  css  js  c++  java
  • Java设计模式之代理模式的动态代理上篇

    前言

    什么是动态代理呢?动态代理指的是在实现阶段不需要关心代理谁,而是在运行阶段才指定哪一个对象。

    动态代理示例

    首先要介绍一下JDK提供的一个动态代理接口 InvocationHandler。这个接口的用途在于对代理类的方法进行代理,我们先实现InvocationHandler接口:

     1 public class ConsumerHandler implements InvocationHandler {
     2 
     3     private Object proxiedInstance = null;
     4 
     5     public ConsumerHandler(Object proxiedInstance) {
     6         this.proxiedInstance = proxiedInstance;
     7     }
     8 
     9     @Override
    10     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    11 
    12         Object proxyInstance = method.invoke(this.proxiedInstance, args);
    13         return proxyInstance;
    14     }
    15 }

    第3行:声明被代理的对象实例。

    第5行:构造行数被代理对象作为形式参数。

    第10行-14行:调用被代理的方法。

    消费者抽象接口和消费者真实角色都没有改动,代码如下图所示:

    1 public interface IConsumer {
    2 
    3     public void login(String name, String password);
    4 
    5     public void order();
    6 
    7     public void pay();
    8 
    9 }
     1 public class RealConsumer implements IConsumer {
     2 
     3     private String name = null;
     4 
     5     public RealConsumer(String name){
     6         this.name = name;
     7     }
     8 
     9     @Override
    10     public void login(String name, String password) {
    11 
    12         System.out.println("登录用户["+name+"]登陆成功");
    13     }
    14 
    15     @Override
    16     public void order() {
    17 
    18         System.out.println("登录账号:"+ this.name +"生成订单成功");
    19 
    20     }
    21 
    22     @Override
    23     public void pay() {
    24 
    25         System.out.println("登录账号:"+ this.name +"订单支付成功");
    26 
    27     }
    28 
    29 }

    OK。这个都没什么问题,最后我们再看看一下动态代理的场景类:

     1 public class Client {
     2 
     3     public static void main(String[] args) {
     4         IConsumer consumer = new RealConsumer("抒尽");
     5 
     6         ConsumerHandler consumerHandler = new ConsumerHandler(consumer);
     7 
     8         ClassLoader classLoader = consumer.getClass().getClassLoader();
     9 
    10         Object o = Proxy.newProxyInstance(classLoader, new Class[]{IConsumer.class}, consumerHandler);
    11         IConsumer proxy = (IConsumer)o;
    12 
    13         proxy.login("shujin", "123456");
    14         proxy.order();
    15         proxy.pay();
    16     }
    17 }

    第4行,定义一个真实消费者[抒尽]

    第6行,定义一个handler

    第8行,获取真实角色的类加载器

    第10行-11行,动态产生一个代理者

    第13行-15行,使用代理者来访问。

    使用动态代理,我们并没有手工去创建一个代理类,更加没有代理类实现抽象接口。这就是动态代理的强大功能,如果我们需要变更需求,只需要修改动态代理实现类即可。

    如果使用InvovationHandler实现动态代理。要产生某个类的代理,这个类必须要有接口

    如何查看动态代理类

    下面我们来看一下这个代理类产生的class文件。首先我们在场景类中main方法中增加系统参数:System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

     1 public static void main(String[] args) {
     2 
     3         System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
     4 
     5         IConsumer consumer = new RealConsumer("抒尽");
     6 
     7         ConsumerHandler consumerHandler = new ConsumerHandler(consumer);
     8 
     9         ClassLoader classLoader = consumer.getClass().getClassLoader();
    10 
    11         Object o = Proxy.newProxyInstance(classLoader, new Class[]{IConsumer.class}, consumerHandler);
    12         IConsumer proxy = (IConsumer)o;
    13 
    14         proxy.login("shujin", "123456");
    15         proxy.order();
    16         proxy.pay();
    17     }

     执行main方法之后,在项目的../com/sun/proxy目录下,会产生一个叫作$Proxy0.class。通过javap -c $Proxy0.class查看文件的字节码:

      1 public final class com.sun.proxy.$Proxy0 extends java.lang.reflect.Proxy implements com.example.pattern.proxy.dynamic.IConsumer {
      2   public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler) throws ;
      3     Code:
      4        0: aload_0
      5        1: aload_1
      6        2: invokespecial #8                  // Method java/lang/reflect/Proxy."<init>":(Ljava/lang/reflect/InvocationHandler;)V
      7        5: return
      8 
      9   public final boolean equals(java.lang.Object) throws ;
     10     Code:
     11        0: aload_0
     12        1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
     13        4: aload_0
     14        5: getstatic     #20                 // Field m1:Ljava/lang/reflect/Method;
     15        8: iconst_1
     16        9: anewarray     #22                 // class java/lang/Object
     17       12: dup
     18       13: iconst_0
     19       14: aload_1
     20       15: aastore
     21       16: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/la
     22 ng/Object;)Ljava/lang/Object;
     23       21: checkcast     #30                 // class java/lang/Boolean
     24       24: invokevirtual #34                 // Method java/lang/Boolean.booleanValue:()Z
     25       27: ireturn
     26       28: athrow
     27       29: astore_2
     28       30: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
     29       33: dup
     30       34: aload_2
     31       35: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
     32       38: athrow
     33     Exception table:
     34        from    to  target type
     35            0    28    28   Class java/lang/Error
     36            0    28    28   Class java/lang/RuntimeException
     37            0    28    29   Class java/lang/Throwable
     38 
     39   public final void pay() throws ;
     40     Code:
     41        0: aload_0
     42        1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
     43        4: aload_0
     44        5: getstatic     #50                 // Field m5:Ljava/lang/reflect/Method;
     45        8: aconst_null
     46        9: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/la
     47 ng/Object;)Ljava/lang/Object;
     48       14: pop
     49       15: return
     50       16: athrow
     51       17: astore_1
     52       18: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
     53       21: dup
     54       22: aload_1
     55       23: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
     56       26: athrow
     57     Exception table:
     58        from    to  target type
     59            0    16    16   Class java/lang/Error
     60            0    16    16   Class java/lang/RuntimeException
     61            0    16    17   Class java/lang/Throwable
     62 
     63   public final void order() throws ;
     64     Code:
     65        0: aload_0
     66        1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
     67        4: aload_0
     68        5: getstatic     #54                 // Field m3:Ljava/lang/reflect/Method;
     69        8: aconst_null
     70        9: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/la
     71 ng/Object;)Ljava/lang/Object;
     72       14: pop
     73       15: return
     74       16: athrow
     75       17: astore_1
     76       18: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
     77       21: dup
     78       22: aload_1
     79       23: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
     80       26: athrow
     81     Exception table:
     82        from    to  target type
     83            0    16    16   Class java/lang/Error
     84            0    16    16   Class java/lang/RuntimeException
     85            0    16    17   Class java/lang/Throwable
     86 
     87   public final java.lang.String toString() throws ;
     88     Code:
     89        0: aload_0
     90        1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
     91        4: aload_0
     92        5: getstatic     #59                 // Field m2:Ljava/lang/reflect/Method;
     93        8: aconst_null
     94        9: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/la
     95 ng/Object;)Ljava/lang/Object;
     96       14: checkcast     #61                 // class java/lang/String
     97       17: areturn
     98       18: athrow
     99       19: astore_1
    100       20: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
    101       23: dup
    102       24: aload_1
    103       25: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
    104       28: athrow
    105     Exception table:
    106        from    to  target type
    107            0    18    18   Class java/lang/Error
    108            0    18    18   Class java/lang/RuntimeException
    109            0    18    19   Class java/lang/Throwable
    110 
    111   public final void login(java.lang.String, java.lang.String) throws ;
    112     Code:
    113        0: aload_0
    114        1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
    115        4: aload_0
    116        5: getstatic     #66                 // Field m4:Ljava/lang/reflect/Method;
    117        8: iconst_2
    118        9: anewarray     #22                 // class java/lang/Object
    119       12: dup
    120       13: iconst_0
    121       14: aload_1
    122       15: aastore
    123       16: dup
    124       17: iconst_1
    125       18: aload_2
    126       19: aastore
    127       20: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/la
    128 ng/Object;)Ljava/lang/Object;
    129       25: pop
    130       26: return
    131       27: athrow
    132       28: astore_3
    133       29: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
    134       32: dup
    135       33: aload_3
    136       34: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
    137       37: athrow
    138     Exception table:
    139        from    to  target type
    140            0    27    27   Class java/lang/Error
    141            0    27    27   Class java/lang/RuntimeException
    142            0    27    28   Class java/lang/Throwable
    143 
    144   public final int hashCode() throws ;
    145     Code:
    146        0: aload_0
    147        1: getfield      #16                 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
    148        4: aload_0
    149        5: getstatic     #71                 // Field m0:Ljava/lang/reflect/Method;
    150        8: aconst_null
    151        9: invokeinterface #28,  4           // InterfaceMethod java/lang/reflect/InvocationHandler.invoke:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/la
    152 ng/Object;)Ljava/lang/Object;
    153       14: checkcast     #73                 // class java/lang/Integer
    154       17: invokevirtual #76                 // Method java/lang/Integer.intValue:()I
    155       20: ireturn
    156       21: athrow
    157       22: astore_1
    158       23: new           #42                 // class java/lang/reflect/UndeclaredThrowableException
    159       26: dup
    160       27: aload_1
    161       28: invokespecial #45                 // Method java/lang/reflect/UndeclaredThrowableException."<init>":(Ljava/lang/Throwable;)V
    162       31: athrow
    163     Exception table:
    164        from    to  target type
    165            0    21    21   Class java/lang/Error
    166            0    21    21   Class java/lang/RuntimeException
    167            0    21    22   Class java/lang/Throwable
    168 
    169   static {} throws ;
    170     Code:
    171        0: ldc           #79                 // String java.lang.Object
    172        2: invokestatic  #85                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
    173        5: ldc           #86                 // String equals
    174        7: iconst_1
    175        8: anewarray     #81                 // class java/lang/Class
    176       11: dup
    177       12: iconst_0
    178       13: ldc           #79                 // String java.lang.Object
    179       15: invokestatic  #85                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
    180       18: aastore
    181       19: invokevirtual #90                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
    182       22: putstatic     #20                 // Field m1:Ljava/lang/reflect/Method;
    183       25: ldc           #92                 // String com.example.pattern.proxy.dynamic.IConsumer
    184       27: invokestatic  #85                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
    185       30: ldc           #93                 // String pay
    186       32: iconst_0
    187       33: anewarray     #81                 // class java/lang/Class
    188       36: invokevirtual #90                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
    189       39: putstatic     #50                 // Field m5:Ljava/lang/reflect/Method;
    190       42: ldc           #92                 // String com.example.pattern.proxy.dynamic.IConsumer
    191       44: invokestatic  #85                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
    192       47: ldc           #94                 // String order
    193       49: iconst_0
    194       50: anewarray     #81                 // class java/lang/Class
    195       53: invokevirtual #90                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
    196       56: putstatic     #54                 // Field m3:Ljava/lang/reflect/Method;
    197       59: ldc           #79                 // String java.lang.Object
    198       61: invokestatic  #85                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
    199       64: ldc           #95                 // String toString
    200       66: iconst_0
    201       67: anewarray     #81                 // class java/lang/Class
    202       70: invokevirtual #90                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
    203       73: putstatic     #59                 // Field m2:Ljava/lang/reflect/Method;
    204       76: ldc           #92                 // String com.example.pattern.proxy.dynamic.IConsumer
    205       78: invokestatic  #85                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
    206       81: ldc           #96                 // String login
    207       83: iconst_2
    208       84: anewarray     #81                 // class java/lang/Class
    209       87: dup
    210       88: iconst_0
    211       89: ldc           #98                 // String java.lang.String
    212       91: invokestatic  #85                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
    213       94: aastore
    214       95: dup
    215       96: iconst_1
    216       97: ldc           #98                 // String java.lang.String
    217       99: invokestatic  #85                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
    218      102: aastore
    219      103: invokevirtual #90                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
    220      106: putstatic     #66                 // Field m4:Ljava/lang/reflect/Method;
    221      109: ldc           #79                 // String java.lang.Object
    222      111: invokestatic  #85                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
    223      114: ldc           #99                 // String hashCode
    224      116: iconst_0
    225      117: anewarray     #81                 // class java/lang/Class
    226      120: invokevirtual #90                 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
    227      123: putstatic     #71                 // Field m0:Ljava/lang/reflect/Method;
    228      126: return
    229      127: astore_1
    230      128: new           #103                // class java/lang/NoSuchMethodError
    231      131: dup
    232      132: aload_1
    233      133: invokevirtual #106                // Method java/lang/Throwable.getMessage:()Ljava/lang/String;
    234      136: invokespecial #109                // Method java/lang/NoSuchMethodError."<init>":(Ljava/lang/String;)V
    235      139: athrow
    236      140: astore_1
    237      141: new           #113                // class java/lang/NoClassDefFoundError
    238      144: dup
    239      145: aload_1
    240      146: invokevirtual #106                // Method java/lang/Throwable.getMessage:()Ljava/lang/String;
    241      149: invokespecial #114                // Method java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V
    242      152: athrow
    243     Exception table:
    244        from    to  target type
    245            0   127   127   Class java/lang/NoSuchMethodException
    246            0   127   140   Class java/lang/ClassNotFoundException
    247 }

    生成的信息比较多,看不懂也没有太大关系,我们挑主要的看。

    第1行,$Proxy0继承自Proxy同时实现接口IConsumer。Proxy类是给创建动态代理时提供了静态的方法,同时也是所有代理类的超类。同时实现了接口IConsumer。这个接口是被代理角色的接口,这也说明,使用JDK的InvocationHander动态代理时,被代理的具体角色一定要有抽象接口

    第9行,equals方法。

    第63行,order方法。

    第111行,login方法。

    第144行,hashcode方法。

    第169行,静态代码块。

    1.被代理类的接口拥有的方法,代理类都会拥有,这个说明了:动态代理是根据被代理的接口生成所有的方法。换而言之,只要确定一个接口,动态代理会告诉我们我已经全部实现了你的所有方法

    2.静态代码块:初始化静态实例包括pay方法,order方法,login方法的Method实例,实例好之后代理类调用被代理类时使用method反射机制调用。我们可以使用idea直接打开class文件。

     1 public final class $Proxy0 extends Proxy implements IConsumer {
     2     private static Method m1;
     3     private static Method m5;
     4     private static Method m3;
     5     private static Method m2;
     6     private static Method m4;
     7     private static Method m0;
     8 
     9     public $Proxy0(InvocationHandler var1) throws  {
    10         super(var1);
    11     }
    12 
    13     public final void login(String var1, String var2) throws  {
    14         try {
    15             super.h.invoke(this, m4, new Object[]{var1, var2});
    16         } catch (RuntimeException | Error var4) {
    17             throw var4;
    18         } catch (Throwable var5) {
    19             throw new UndeclaredThrowableException(var5);
    20         }
    21     }
    22     
    23     //此处省略其他方法...
    24  
    25 
    26     static {
    27         try {
    28             m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
    29             m5 = Class.forName("com.example.pattern.proxy.dynamic.IConsumer").getMethod("pay");
    30             m3 = Class.forName("com.example.pattern.proxy.dynamic.IConsumer").getMethod("order");
    31             m2 = Class.forName("java.lang.Object").getMethod("toString");
    32             m4 = Class.forName("com.example.pattern.proxy.dynamic.IConsumer").getMethod("login", Class.forName("java.lang.String"), Class.forName("java.lang.String"));
    33             m0 = Class.forName("java.lang.Object").getMethod("hashCode");
    34         } catch (NoSuchMethodException var2) {
    35             throw new NoSuchMethodError(var2.getMessage());
    36         } catch (ClassNotFoundException var3) {
    37             throw new NoClassDefFoundError(var3.getMessage());
    38         }
    39     }
    40 }

    第26行,静态方法,通过类的反射机制得到Method。

    第15行, super.h。父类是proxy。受保护的属性Invocation。然后再调用我们Invocation的实现类ConsumerHandler中的invoke方法。看到这里,应该都想到了吧,只要有扩展,我们只需要的invoke方法中去扩展,答应时间,增加日志等等。

    Proxy中的受保护的属性InvocationHandler又是什么时候初始化进去的呢?Proxy中提供了一个静态方法newProxyInstance();public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);实际上从根本上讲,这不就是创建一个代理的产品吗?这难道不就是弱化的工厂模式吗?

     
  • 相关阅读:
    Combine 框架,从0到1 —— 4.在 Combine 中使用计时器
    Combine 框架,从0到1 —— 4.在 Combine 中使用通知
    Combine 框架,从0到1 —— 3.使用 Subscriber 控制发布速度
    Combine 框架,从0到1 —— 2.通过 ConnectablePublisher 控制何时发布
    使用 Swift Package Manager 集成依赖库
    iOS 高效灵活地配置可复用视图组件的主题
    构建个人博客网站(基于Python Flask)
    Swift dynamic关键字
    Swift @objcMembers
    仅用递归函数操作逆序一个栈(Swift 4)
  • 原文地址:https://www.cnblogs.com/sunshine798798/p/10043369.html
Copyright © 2011-2022 走看看