java动态代理
1.什么是动态代理
动态代理,就是在运行时,基于一个类,动态生成一个代理类,以增强被代理类的功能。最著名的动态代理就是AOP,在被代理类的方法调用开始之前和调用结束之后,做一些通用的工作,比如打印日志、捕获异常等等。
当然有动态代理就有静态代理(设计模式中的代理模式)。
2.一个动态代理使用的实例
接口:
public interface Worker { void work(); }
接口实现的类:
public class WorkerImpl implements Worker { public void work() { System.out.println("我正在工作!"); } public void work2() { System.out.println("我正在工作2!"); } }
动态生成的类:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicWorker implements InvocationHandler { private Object obj; public DynamicWorker(Object obj) { this.obj = obj; } public DynamicWorker(Class clazz) throws Exception { this(clazz.newInstance()); } public DynamicWorker(String className) throws Exception { this(Class.forName(className)); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始工作之前,我要准备工具!"); method.invoke(obj, args); System.out.println("完成工作之后,收拾好工具!"); return null; } }
测试类:
import org.apache.commons.lang3.StringUtils; import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) throws Exception { String className = WorkerImpl.class.getName(); DynamicWorker dynamicWorker = new DynamicWorker(className); Worker worker = (Worker)Proxy.newProxyInstance(WorkerImpl.class.getClassLoader(), WorkerImpl.class.getInterfaces(), dynamicWorker); worker.work(); worker.work2(); System.out.println("worker是不是WorkerImpl的实例--->" + (worker instanceof WorkerImpl)); System.out.println("worker对应的类为--->" + worker.getClass().getSimpleName()); System.out.println("worker继承的父类为--->" + worker.getClass().getSuperclass().getSimpleName()); System.out.println("worker实现的接口为--->" + StringUtils.join(worker.getClass().getInterfaces(), ",")); System.out.println("worker所有的属性为--->\n" + StringUtils.join(worker.getClass().getDeclaredFields(), "\n")); System.out.println("worker所有的方法为--->\n" + StringUtils.join(worker.getClass().getDeclaredMethods(), "\n")); } }
运行的结果:
开始工作之前,我要准备工具! 我正在工作! 完成工作之后,收拾好工具! 开始工作之前,我要准备工具! 我正在工作2! 完成工作之后,收拾好工具! worker是不是WorkerImpl的实例--->false worker对应的类为--->$Proxy0 worker继承的父类为--->Proxy worker实现的接口为--->interface com.taobao.zhenge.java.proxy.Worker worker所有的属性为---> private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m1 private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m3 private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m4 private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m2 private static java.lang.reflect.Method com.sun.proxy.$Proxy0.m0 worker所有的方法为---> public final boolean com.sun.proxy.$Proxy0.equals(java.lang.Object) public final java.lang.String com.sun.proxy.$Proxy0.toString() public final int com.sun.proxy.$Proxy0.hashCode() public final void com.sun.proxy.$Proxy0.work() public final void com.sun.proxy.$Proxy0.work2()
从上面的例子可以看出,动态代理可以实现什么样的功能。
总结如下:
1.两个重要的类:Proxy和InvocationHandler
Proxy:生成代理类的入口,一些具体测策略和逻辑都在这个类中
InvocationHandler:用来对被代理类做增强处理,需要引用被代理类的实例(一般通过反射获取)
2.动态代理是基于接口做的代理
1)被代理类必须要实现接口
2)代理类只能增强接口对应的方法(可以有多个方法),不能增加非接口方法
3.动态代理生成的类到底是什么样子的
jdk中动态代理底层是调用ProxyGenerator.generateProxyClass去生成class文件的字节码的,如下代码所示:
mport sun.misc.ProxyGenerator; import java.io.FileOutputStream; import java.lang.reflect.Modifier; public class GenerateClass { public static void main(String[] args) throws Exception { String className = "com.taobao.test.ProxyClass"; Class[] interfaces = new Class[]{Worker.class}; int accessFlags = Modifier.PUBLIC | Modifier.FINAL; byte[] classByte = ProxyGenerator.generateProxyClass(className, interfaces, accessFlags); FileOutputStream fos = new FileOutputStream("ProxyClass"); fos.write(classByte); fos.close(); } }
三个参数中:
className:生成代理类的完整类名
interfaces:代理类实现的接口(这也说明,java的动态代理只能代理实现了接口的代理类)
accessFlags:类的修饰符,public等
最后将生成的class字节码保存到文件中。
反编译后得到的代码:
package com.taobao.test; import com.taobao.test.Worker; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class ProxyClass extends Proxy implements Worker { private static Method m1; private static Method m3; private static Method m4; private static Method m2; private static Method m0; public ProxyClass(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void work() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void work2() throws { try { super.h.invoke(this, m4, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } 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)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m3 = Class.forName("com.taobao.test.Worker").getMethod("work", new Class[0]); m4 = Class.forName("com.taobao.test.Worker").getMethod("work2", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
InvocationHandler在哪里?动态代理类继承自Proxy,Proxy中引用了InvocationHandler。
从反编译得到的结果可以很清晰的看出动态代理生成类的结构。
4.动态代理源码解析
上面以及提到动态代理涉及到两个核心类,Proxy和InvocationHandler,其中InvocationHandler非常简单,用于增加代理类的功能,需要根据自己的实际需求去扩展,这里主要解析Proxy是怎样生成动态代理类的,从入口(Proxy.newProxyInstance)开始:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
接口的三个参数:
loader:代理类对应的ClassLoader
interfaces:代理类实现的接口
h:InvocationHandler,具体实现了如何增强代理类
整个过程大致可以分成三个步骤:
1.根据loader和interfaces生成对应的Class对象
Class对象的生成逻辑全部在ProxyClassFactory中,底层就是调用ProxyGenerator.generateProxyClass去生成class文件的字节码
2.找到Class对象中以InvocationHandler为参数的构造方法
3.使用反射生成对应的对象
关于源码的详细细节,可以参考这篇文章

浙公网安备 33010602011771号