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

 
posted @ 2018-11-30 12:26  冰糖小城  阅读(262)  评论(0编辑  收藏  举报