Java动态代理研究
浅说动态代理 关于java的代理模式,此处不过多讲解。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。动态代理指被代理者委托代理者完成相应的功能,是拦截器的一种实现方式,其用于拦截类或接口,内部可通过判断实现对某个方法的拦截。 日常使用中可能经常需要在方法调用时进行拦截,如调用前记录一下调用开始时间,调用结束后记录结束时间,就可以很方便的计算出调用方法的业务逻辑处理耗时。 动态代理使用 简单的看下最简单的使用: 编写一个接口: package my.java.reflect.test; public interface Animal { void sayHello(); } 委托类 public class Dog implements Animal { public void sayHello() { System.out.println("wang wang!"); } } 拦截器 package my.java.reflect.test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MyInvocationHandler implements InvocationHandler { private Object target; public Object bind(Object realObj) { this.target = realObj; Class<?>[] interfaces = target.getClass().getInterfaces(); ClassLoader classLoader = this.getClass().getClassLoader(); return Proxy.newProxyInstance(classLoader, interfaces, this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("proxy method"); return method.invoke(target, args); } } 测试类 package my.java.reflect.test; import org.junit.Test; public class ProxyTest { @Test public void testNewProxyInstance() { Dog dog = new Dog(); Animal proxy = (Animal) new MyInvocationHandler().bind(dog); proxy.sayHello(); } } 输出 proxy method wang wang! 动态代理原理总结 之所以将原理先总结了,因为希望把原理先用最简洁的语言说清楚,再来深入分析,否则在深入分析阶段粘贴过多的源码可能会导致阅读兴趣下降。 通过Proxy#newProxyInstance方法得到代理对象实例; 这个代理对象有着和委托类一模一样的方法; 当调用代理对象实例的方法时,这个实例会调用你实现InvocationHandler里的invoke方法。 而这里,最复杂的显然是得到代理对象实例了,怎么得到的呢?来,看看源码! 动态代理原理 要了解java动态代理的原理只要从Proxy#newProxyInstance入手即可。 先看newProxyInstance方法,关注有中文注释的地方即可 @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) {// 没有实现InvocationHandler,直接失败 throw new NullPointerException(); } 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对象 */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { // 拿到代理对象的构造方法 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { return newInstance(cons, ih); } }); } else { // 构造出代理对象实例 return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } } // 利用反射调用构造方法,产生代理实例,没什么好说的 private static Object newInstance(Constructor<?> cons, InvocationHandler h) { try { return cons.newInstance(new Object[] {h} ); } catch (IllegalAccessException | InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString()); } } } 以上这段代码的核心在 /* * Look up or generate the designated proxy class. * 查找或者生成代理类的Class对象 */ Class<?> cl = getProxyClass0(loader, intfs); 查看getProxyClass0方法 private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) { if (interfaces.length > 65535) {// 你的类如果实现了超过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 // 如果委托类的接口已经存在于缓存中,则返回,否则利用ProxyClassFactory产生一个新的代理类的Class对象 return proxyClassCache.get(loader, interfaces); } 这段话的核心很显然就是proxyClassCache.get(loader, interfaces),其中proxyClassCache是一个缓存: /** * a cache of proxy classes */ private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); 继续看proxyClassCache.get(loader, interfaces),对应的是java.lang.reflect.WeakCache<K, P, V>#get,一大段代码就为了返回一个代理类的Class对象,关注中文注释处即可: public V get(K key, P parameter) { Objects.requireNonNull(parameter); expungeStaleEntries(); Object cacheKey = CacheKey.valueOf(key, refQueue); // lazily install the 2nd level valuesMap for the particular cacheKey ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey); if (valuesMap == null) { ConcurrentMap<Object, Supplier<V>> oldValuesMap = map.putIfAbsent(cacheKey, valuesMap = new ConcurrentHashMap<>()); if (oldValuesMap != null) { valuesMap = oldValuesMap; } } // create subKey and retrieve the possible Supplier<V> stored by that // subKey from valuesMap Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter)); Supplier<V> supplier = valuesMap.get(subKey); Factory factory = null; while (true) { if (supplier != null) { // supplier might be a Factory or a CacheValue<V> instance // 关键点在这里 V value = supplier.get(); if (value != null) { return value; } } // else no supplier in cache // or a supplier that returned null (could be a cleared CacheValue // or a Factory that wasn't successful in installing the CacheValue) // lazily construct a Factory if (factory == null) { factory = new Factory(key, parameter, subKey, valuesMap); } if (supplier == null) { supplier = valuesMap.putIfAbsent(subKey, factory); if (supplier == null) { // successfully installed Factory supplier = factory; } // else retry with winning supplier } else { if (valuesMap.replace(subKey, supplier, factory)) { // successfully replaced // cleared CacheEntry / unsuccessful Factory // with our Factory supplier = factory; } else { // retry with current supplier supplier = valuesMap.get(subKey); } } } } 这段代码的核心就在V value = supplier.get();,通过这段代码,代理类的Class的对象就出来了。 查看subKeyFactory.apply(key, parameter),这段代码还是在WeakCache里: @Override public synchronized V get() { // serialize access // re-check Supplier<V> supplier = valuesMap.get(subKey); if (supplier != this) { // something changed while we were waiting: // might be that we were replaced by a CacheValue // or were removed because of failure -> // return null to signal WeakCache.get() to retry // the loop return null; } // else still us (supplier == this) // create new value V value = null; try { // 核心点在这里 value = Objects.requireNonNull(valueFactory.apply(key, parameter)); } finally { if (value == null) { // remove us on failure valuesMap.remove(subKey, this); } } // the only path to reach here is with non-null value assert value != null; // wrap value with CacheValue (WeakReference) CacheValue<V> cacheValue = new CacheValue<>(value); // try replacing us with CacheValue (this should always succeed) if (valuesMap.replace(subKey, this, cacheValue)) { // put also in reverseMap reverseMap.put(cacheValue, Boolean.TRUE); } else { throw new AssertionError("Should not reach here"); } // successfully replaced us with new CacheValue -> return the value // wrapped by it return value; } 回看proxyClassCache可以知道valueFacotry对应的是ProxyClassFactory类,这是java.reflect.Proxy的内部类: @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader);// 看下接口对应的类文件有没有被ClassLoader加载 } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) {// 看下是不是都是接口 throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {// 接口不能重复 throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same package. */ for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) {// 接口不是public的,截取包名,保证代理类跟委托类同一个包下 String name = intf.getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( "non-public interfaces from different packages"); } } } if (proxyPkg == null) {// 是public的接口,拼接成com.sun.proxy$Proxy,再拼接一个数字 // if no non-public proxy interfaces, use com.sun.proxy package proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * 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); try { // 根据字节码生成代理类Class对象,native方法,看过类加载器的童鞋应该不陌生 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生成代理类的字节码数组,接着将字节码封装成Class对象,就是代理类的Class对象了。生成字节码数组的代码就不详细说了。 将字节码数组写到文件里查看一下: byte[] data = ProxyGenerator.generateProxyClass(“Animal$Proxy”, new Class[] { Animal.class }); FileOutputStream out = new FileOutputStream("Animal$Proxy.class"); out.write(data); 利用jd-gui反编译工具可以看看代理类的源码: import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class Animal$Proxy extends Proxy implements my.java.reflect.test.Animal { private static Method m3; private static Method m1; private static Method m0; private static Method m2; public Animal$Proxy(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); } public final void sayHello() { try { this.h.invoke(this, m3, null); return; } catch (Error | RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final boolean equals(Object paramObject) { try { return ((Boolean) this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (Error | RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() { try { return ((Integer) this.h.invoke(this, m0, null)).intValue(); } catch (Error | RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() { try { return (String) this.h.invoke(this, m2, null); } catch (Error | RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static { try { m3 = Class.forName("my.java.reflect.test.Animal").getMethod("sayHello", new Class[0]); m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } } 可以看到生成的代理类有一个构造方法,参数是InvocationHandler,然后回看我们第一步分析的时候,得到代理类的Class对象后,会通过反射得到代理类的构造方法,接着调用构造方法,参数就是InvocationHandler。 在代理类的源码里,最值得注意的就是m3,这个对应的是Animal的sayHello方法,当我们通过MyInvocationHandler#bind方法得到代理对象实例后,调用代理对象Animal$Proxy的sayHello方法,就会执行: public final void sayHello() { try { this.h.invoke(this, m3, null); return; } catch (Error | RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } 正好是我们在MyInvocationHandler实现的invoke方法,这样就完成了代理的功能。 用一个总结收尾 之所以将原理先总结了,因为希望把原理先用最简洁的语言说清楚,再来深入分析,否则在深入分析阶段粘贴过多的源码可能会导致阅读兴趣下降。 通过Proxy#newProxyInstance方法得到代理对象实例; 这个代理对象有着和委托类一模一样的方法; 当调用代理对象实例的方法时,这个实例会调用你实现InvocationHandler里的invoke方法。 这里面无疑第一步是最复杂的,这里大概经历了: 利用参数中的接口,通过缓存或者利用ProxyGenerator生成字节码并生成代理类的Class对象; 通过反射得到代理对象的构造方法; 通过构造方法和InvocationHandler参数通过反射实例化出代理对象实例。