JDK动态代理源码解析——ProxyWeakCacheProxyGenerator
Posted rotk2015
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK动态代理源码解析——ProxyWeakCacheProxyGenerator相关的知识,希望对你有一定的参考价值。
-
JDK版本为RedHat OpenJDK 1.8.0_282。
-
JDK中的动态代理Proxy类仅限于方法拦截,且只能代理实现了接口的对象。
-
调用Proxy的静态方法创建——继承了Proxy类的代理类(java只支持单继承,这就是为什么要求被代理类必须实现接口),通过该代理类的构造器创建对应代理对象,该对象实现了被代理类的接口,仅起到接口的作用。
-
代理类对象内持有一个——实现了InvocationHandler接口的对象(我们称它为中间对象吧)的引用,中间对象又持有一个被代理对象的引用。中间对象是真正办事的对象,对代理类对象的所有方法调用都会转发给中间对象,由中间对象的invoke方法实现,而中间对象的 invoke 方法,通过反射调用了被代理对象的对应方法。
-
以上是从整体的角度介绍,下面从介绍下具体代码。
interface Animal public void speak(); class Dog implements Animal @Override public void speak() System.out.println("I am a dog."); class DogHandler implements InvocationHandler private Object obj; public dogHandler(Object obj) this.obj = obj; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable System.out.println("In a handler."); method.invoke(obj, args); System.out.println(obj.toString()); return proxy; public class test public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException Dog aDog = new Dog(); DogHandler h = new DogHandler(aDog); // Animal pxyDog = (Animal) Proxy.newProxyInstance(dog.class.getClassLoader(), // dog.class.getInterfaces(), h); Class pxyDogClazz = Proxy.getProxyClass(Dog.class.getClassLoader(), Dog.class.getInterfaces()); Constructor pxyDogCons = pxyDogClazz.getConstructor(InvocationHandler.class); Animal pxyDog = (Animal) pxyDogCons.newInstance(h); pxyDog.speak();
-
Proxy提供了两种方式创建代理对象,getProxyClass()创建代理类 + getConstructor() 反射获取构造器对象 + newInstance()创建实例,以及将其与对应对应异常处理代码打包在一块的,newProxyInstance()。
-
getProxyClass() 接受类加载器与接口类型,实质是在内部调用getProxyClass0(),而后者则是向内部成员 proxyClassCache 申请,proxyClassCache 是一个缓存,如果之前创建过对应的代理类,则直接返回,否则创建。
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) checkProxyAccess(Reflection.getCallerClass(), loader, intfs); return getProxyClass0(loader, intfs); /** 1. Generate a proxy class. Must call the checkProxyAccess method 2. to perform permission checks before calling this. */ private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) if (interfaces.length > 65535) throw new IllegalArgumentException("interface limit exceeded"); // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory return proxyClassCache.get(loader, interfaces); /** * a cache of proxy classes */ private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
-
注意到,调用 proxyClassCache.get(loader, interfaces) 返回代理类,而 proxyClassCache 是 WeakCache 类,在构造时传入了 KeyFactory、ProxyClassFactory 对象(均为Proxy的静态私有类)。阅读源码可发现,WeakCache 类中,KeyFactory 被 subKeyFactory 引用,ProxyClassFactory 被 valueFactory 引用。
/** * Construct an instance of @code WeakCache * * @param subKeyFactory a function mapping a pair of * @code (key, parameter) -> sub-key * @param valueFactory a function mapping a pair of * @code (key, parameter) -> value * @throws NullPointerException if @code subKeyFactory or * @code valueFactory is null. */ public WeakCache(BiFunction<K, P, ?> subKeyFactory, BiFunction<K, P, V> valueFactory) this.subKeyFactory = Objects.requireNonNull(subKeyFactory); this.valueFactory = Objects.requireNonNull(valueFactory);
-
考虑到 WeakCache 类源码有点复杂,下面不贴代码,仅用文字描述其逻辑,感兴趣的读者可去看看具体代码。
-
当我们调用 proxyClassCache.get(loader, interfaces)时, 发生了什么?
-
首先,将 loader(类加载器)作为 key,生成 cacheKey,在 map(ConcurrentMap)中获取对应值 valuesMap(也是ConcurrentMap),这一步实际上就是在找类加载器对应的那个哈希图。
-
然后,利用 loader、interfaces(接口类型)通过 subKeyFactory(也就是KeyFactory) 生成 subKey,利用 subKey 在 valuesMap 中获取对应工厂 supplier。
-
紧接着,调用 supplier.get() 即可生成对应代理类。这里的 subpplier 是接口引用,引用的是 Factory 对象。而 Factory 是 WeakCache 的私有静态类,重写了 get() 方法,使得在 get() 内部,将 loader、interfaces 传递给 WeakCache 的 valueFactory(也就是ProxyClassFactory) 的 apply() 方法,并返回其返回值。
-
终于到了这一步,可以看出,我们的代理类是由这个 ProxyClassFactory 负责生成的。而 ProxyClassFactory 具体干了这么些事:定义代理类名称 proxyName($ProxyN,N为生成代理类的序号,0始),调用 ProxyGenerator 的 generateProxyClass() 生成字节流 proxyClassFile,最后调用本地方法 defineClass0() 将 proxyClassFile 还原成Class。
/** * A factory function that generates, defines and returns the proxy class given * the ClassLoader and array of interfaces. */ private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> // prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) //_____SOME CODES ELSE_____ /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); catch (ClassFormatError e) /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString());
-
ProxyGenerator 位于 package sun.misc 内,JDK文档查不到对应资料。ProxyGenerator 内的 generateProxyClass() 调用 generateClassFile() 生成字节流文件。在生成代理类的字节流的过程中,除了添加接口的方法外,还调用 generateConstructor() 生成并添加代理类的构造器方法(这就是之前 getConstructor() 反射获取的),调用 generateStaticInitializer() 生成并添加静态初始化方法,以及hashCode()、equals()、toString()。
另:在生成代理类的构造器时,添加了父类——即 Proxy 的构造器(相当于 super()),而在 Proxy 类中,有两个 protected 成员:
/** * the invocation handler for this proxy instance. * @serial */ protected InvocationHandler h; /** * Constructs a new @code Proxy instance from a subclass * (typically, a dynamic proxy class) with the specified value * for its invocation handler. * * @param h the invocation handler for this proxy instance * * @throws NullPointerException if the given invocation handler, @code h, * is @code null. */ protected Proxy(InvocationHandler h) Objects.requireNonNull(h); this.h = h;
-
说了这么多,这个生成的代理类究竟是什么样子呢?我们在main函数开始加上如下代码,然后运行main函数即可在项目下生成并保存 $Proxy0.class 文件,将其拖到IDEA中会自动反编译出对应.java文件。
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
-
$Proxy0代码:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package myBoard; 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 Animal private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(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 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 void speak() throws try super.h.invoke(this, m3, (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")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m3 = Class.forName("myBoard.Animal").getMethod("speak"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); catch (NoSuchMethodException var2) throw new NoSuchMethodError(var2.getMessage()); catch (ClassNotFoundException var3) throw new NoClassDefFoundError(var3.getMessage());
-
可以看到,
1.$Proxy0构造函数的实现完全依托于父类Proxy(详见第14条);
2.内部实现除了接口方法外,也如之前所说实现了hashCode()、equals()、toString();
3.每个方法的实现方式都是 super.h.invoke(this,mN,…),即调用继承自父类的 protected 成员 h(再见第14条,首 尾 呼 应);
4.传递给h.invoke()的,除了必要的方法信息,还有本代理类对象的引用 this,这就解释了 InvocationHandler 的 invoke 方法的第一个形参 Object proxy 到底是什么。
参考资料:
以上是关于JDK动态代理源码解析——ProxyWeakCacheProxyGenerator的主要内容,如果未能解决你的问题,请参考以下文章