• 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);实际上从根本上讲,这不就是创建一个代理的产品吗?这难道不就是弱化的工厂模式吗?

     

  • 相关阅读:
    Android MVP架构分析
    JavaEE基本了解
    学习面试题Day09
    使用反射来实现简单工厂模式
    Android Material Design简单使用
    c语言 找最小值
    c++ 计算指定半径圆的面积
    c++ 字符串拷贝以及合并
    python yaml文件读写
    python 列表元素替换以及删除
  • 原文地址:https://www.cnblogs.com/candies123/p/10043369.html
Copyright © 2020-2023  润新知