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