深入Java动态代理源码
背景介绍
什么是动态代理?
动态代理,本质上还是代理模式,只不过代理类是在JDK内部产生并创建实例(字节码编辑)。再者其内部还维护了一个基于弱引用的缓存结构。总结来说:动态代理 = 代理模式 + 字节码编辑 + 弱引用缓存。
我们来探究一下这个过程。
原理探究
示例代码:
public class TestProxy {interface Hello {void hello();}private static class HelloImpl implements Hello {public void hello() {System.out.println("hello");}}public static void main(String[] args) {Hello hello = new HelloImpl();Class<? extends Hello> clazz = hello.getClass();Hello proxy = (Hello)Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(), new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//String name = method.getName();if ("hello".equals(name)) {//System.out.println("xxx");}return null;}});proxy.hello();}}
调用关系:
弱引用WeakReference
WeakCache基于弱引用的缓存结构。
构造如下:
public WeakCache(BiFunction<K, P, ?> subKeyFactory,BiFunction<K, P, V> valueFactory) {this.subKeyFactory = Objects.requireNonNull(subKeyFactory);this.valueFactory = Objects.requireNonNull(valueFactory);}
其中的subKeyFactory为Proxy.KeyFactory;valueFactory为Proxy.ProxyClassFactory。二者都实现了BiFunction接口,简单工厂的实现。
核心数据结构:
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map= new ConcurrentHashMap<>();
两层Map的结构:
第一层的key:CacheKey类型,继承WeakReference,使用其valueOf()创建实例(简单工厂模式)。
第一层的value:Map结构,即第二层。
第二层的key:类型可以为:Key1 Key2 KeyN 和Object(key0),不一定会继承WeakReference。通过subKeyFactory创建对象。
第二层的value:CacheValue类型,继承WeakReference,使用构造方法创建,参数为valueFactory创建的对象。
简单工厂+函数接口
Proxy.KeyFactory和Proxy.ProxyClassFactory都是简单工厂,分别用于创建key和value对象;其实现BiFunction接口,以BiFunction的apply()作为工厂的方法。
字节码编辑技术
ProxyGenerator#generateProxyClass()是基于字节码编辑技术直接产生字节码,我我们可以通过如下代码,反编译查看一下生成的class文件的源代码:
测试代码:
byte[] bytes = ProxyGenerator.generateProxyClass("xxx$Proxy", clazz.getInterfaces(), 16);Path path = Paths.get("/Users/xwei/Desktop/Proxy.class");try {Files.createFile(path);OutputStream outputStream = Files.newOutputStream(path, StandardOpenOption.WRITE);outputStream.write(bytes);outputStream.close();} catch (IOException e) {e.printStackTrace();}
反编译之后的代理类的源代码:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//import com.proxy.TestProxy.Hello;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;final class xxx$Proxy extends Proxy implements Hello {private static Method m1;private static Method m3;private static Method m2;private static Method m0;public xxx$Proxy(InvocationHandler var1) throws {super(var1);}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 void hello() throws {try {super.h.invoke(this, m3, (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);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m3 = Class.forName("com.proxy.TestProxy$Hello").getMethod("hello");m2 = Class.forName("java.lang.Object").getMethod("toString");m0 = Class.forName("java.lang.Object").getMethod("hashCode");} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}}
