简介
说明
本文用示例介绍Java代理模式(动态代理)的JDK写法。
优缺点
优点
- 可以看到生成的代理类,有利于理解JDK代理模式的原理。
缺点
- 只能代理实现了接口的类。
- 写起来比较麻烦。
JDK动态代理的原理简述
生成的代理类继承Proxy,且实现了业务的接口,Proxy中有InvocationHandler的实现类的引用。
调用被代理的类的方法时,会调用父类(Proxy)的InvocationHandler成员的invoke方法。
实例
动态代理具体步骤:
- 通过实现 InvocationHandler 接口创建自己的调用处理器;
- 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
实例1:统计执行时间
需求:统计某个类所有方法的执行时间。
源码地址
原始的任务
接口
package com.knife.designPattern.origin; /** * 任务接口 */ public interface Task { void dealTask(String taskName); void sayHello(String name); }
实现类
package com.knife.designPattern.origin.impl; import com.knife.designPattern.origin.Task; public class TaskImpl implements Task { @Override public void dealTask(String taskName) { System.out.println("开始运行任务: " + taskName); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void sayHello(String name) { System.out.println("你好" + name); } }
代理类
代理类
package com.knife.designPattern.proxy; import com.knife.designPattern.origin.Task; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class TaskProxy implements InvocationHandler { private Object delegate = null; public TaskProxy(Task delegate) { this.delegate = delegate; } // proxy:代理类代理的真实代理对象。例如:com.sun.proxy.$Proxy0 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long startTime = System.currentTimeMillis(); Object result = method.invoke(delegate, args); long endTime = System.currentTimeMillis(); System.out.println("运行时间: " + (endTime - startTime) + " ms"); return result; } }
代理工厂
package com.knife.designPattern.proxy; import com.knife.designPattern.origin.Task; import com.knife.designPattern.origin.impl.TaskImpl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicProxyFactory { public static Task getInstance() { Task origin = new TaskImpl(); InvocationHandler handler = new TaskProxy(origin); return (Task) Proxy.newProxyInstance( origin.getClass().getClassLoader(), origin.getClass().getInterfaces(), handler); } }
测试
package com.knife.designPattern; import com.knife.designPattern.origin.Task; import com.knife.designPattern.proxy.DynamicProxyFactory; public class Demo{ public static void main(String[] args) { System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); Task proxy = DynamicProxyFactory.getInstance(); System.out.println("代理类:" + proxy.getClass()); System.out.println("-----------------------------------"); proxy.dealTask("测试任务"); } }
运行结果
代理类:class com.sun.proxy.$Proxy0 ----------------------------------- 开始运行任务: 测试任务 运行时间: 510 ms
实例2:代理ArrayList的方法
package org.example.a; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; public class Demo { public static void main(String[] args) { final ArrayList<String> list = new ArrayList<>(); List<String> listProxy=(List<String>) Proxy.newProxyInstance( list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(list,args); } }); listProxy.add("hello") ; listProxy.add("world") ; System.out.println(list); } }
运行结果
[hello, world]
原理
相关类
InvocationHandler
package java.lang.reflect; public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
Proxy
package java.lang.reflect; public class Proxy implements java.io.Serializable { private static final long serialVersionUID = -2222568056686623797L; /** parameter types of a proxy class constructor */ private static final Class<?>[] constructorParams = { InvocationHandler.class }; /** * a cache of proxy classes */ private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); /** * the invocation handler for this proxy instance. * @serial */ protected InvocationHandler h; /** * Prohibits instantiation. */ private Proxy() { } // 其他代码 }
生成的代理类的源码
查看自动生成的proxy class
默认在运行时程序自动生成proxy class,若想看下自动生成的proxy class有三种方法
- 设置参数-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
- 程序里调用:System.setProperty(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
- 在程序中直接调用ProxyGenerator.generateProxyClass()来生成动态代理类,如下所示:
String name = "$Proxy00"; byte[] data = ProxyGenerator.generateProxyClass("com.sun.proxy." + name, new Class[] { Hello.class } ); FileOutputStream out = new FileOutputStream("/tmp/" + name + ".class" ); out.write(data); out.close();
以前边的“时间统计示例”为例,在main方法中最前边添加
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
执行结果:生成了$Proxy0.class
$Proxy0.class代码如下
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.example.a; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; final class $Proxy0 extends Proxy implements ExecutionTime { private static Method m1; private static Method m4; private static Method m2; private static Method m3; private static Method m0; static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m4 = Class.forName("org.example.a.ExecutionTime").getMethod("sayHello", Class.forName("java.lang.String")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("org.example.a.ExecutionTime").getMethod("dealTask", Class.forName("java.lang.String")); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } public $Proxy0(InvocationHandler var1) throws { super(var1); } public final void dealTask(String var1) throws { try { super.h.invoke(this, m3, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void sayHello(String var1) throws { try { super.h.invoke(this, m4, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } 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 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); } } }
JDK动态代理只能代理接口
类Proxy的作用是保存自定义的InvocationHandler,便于在方法代理时执行自定义InvocationHandler的逻辑。由于$Proxy0已经继承了类Proxy,所以不能再extends一个类了,所以只能implements一个接口了。
执行流程
创建代理类
Proxy.newProxyInstance时,入参:代理类的类加载器和接口、InvocationHandler接口的实现类。返回:proxy(Proxy$0类型)
执行流程
proxy.dealTask(Proxy$0的dealTask方法) // Proxy类的h(前边保存的InvocationHandler接口对象)的invoke方法 // m1是通过反射获得的方法,var1是传进来的String类型的参数 super.h.invoke(this, m1, new Object[]{var1}) ExecutionTimeProxy(InvocationHandler接口对象)的invoke方法 // Method类的invoke方法 method.invoke(delegate, args);
生成Proxy.class的流程
Proxy.newProxyInstance=> ProxyClassFactory.apply=> ProxyGenerator.generateProxyClass=> .class文件=> Class对象=> Proxy实例
关于ProxyGenerator.generateProxyClass(),内部主要是按照固定”模板“按照字节码格式生成对应class字节码,大致是:实现要代理接口的所有public方法及固定的方法(hashCode、equals和toString),然后调用InvocationHandler的invoke方法。(就是走到示例代码中的HelloProxy类(class HelloProxy implements InvocationHandler)。
请先
!