谈点动态代理
java里的动态代理一般有jdk的动态代理和cglib实现的动态代理两种,用起来也蛮好用的,也一直没有深究实现原理,今天心血来潮就看看他们的实现。
jdk的动态代理类需要实现InvocationHandler这个接口,然后在invoke方法里调用被代理类的方法,方法前后可以做任何你想做的操作。调用时候用如下方式调用:
InvocationHandler handler = new MyInvocationHandler(...); Class proxyClass = Proxy.getProxyClass( Foo.class.getClassLoader(), new Class[] { Foo.class }); Foo f = (Foo) proxyClass. getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler });
或者更简单的:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler);
可以看到jdk实现的动态代理,被代理类必须要实现接口,这是jdk和cglib实现动态代理的一个区别。那么它是怎么实现的呢,打开Proxy类的源码,查看newProxyInstance方法,可以看到它先通过final Class<?>[] intfs = interfaces.clone()获取到一个Class数组,然后调用getProxyClass0(loader, intfs);获取到一个Class,之后获取这个Class的构造器:final Constructor<?> cons = cl.getConstructor(constructorParams);最后return一个构造器构造出的实例cons.newInstance(new Object[]{h})。那么问题就在于这个获取到的Class是什么,其实在实现里头,把这个获取到的Class打印出来,会发现是这么一个玩意com.sun.proxy.$Proxy0,那么这是怎么来的呢,我们看getProxyClass0方法。
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); }
可以看到注释里写的,如果这个代理类存在缓存里,就从缓存里获取,否则通过ProxyClassFactory去创建一个,这个代码就不贴了,最后是通过一个本地方法生成的这个代理类。这个代理类大概长成这样:
public final class $Proxy0 extends Proxy implements ISubject { 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 hello(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 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("com.studytest.www.ISubject").getMethod("hello", 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()); } } }
可以看到它实现了Object类的toString,hashCode和equals方法,当调用我的hello方法的时候,会去调代理类的invoke方法。
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它通过继承方式实现代理。假设有个类HelloConcrete
public class HelloConcrete { public String sayHello(String str) { return "HelloConcrete: " + str; } }
然后实现一个MyMethodInterceptor
public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("dabenzhu"); return methodProxy.invokeSuper(o, objects); } }
最后来个测试
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloConcrete.class); enhancer.setCallback(new MyMethodInterceptor()); HelloConcrete hello = (HelloConcrete)enhancer.create(); System.out.println(hello.getClass()); System.out.println(hello.sayHello("I love you!"));
动态代理就完成了,我们打印了这个代理生成的class,发现是HelloConcrete$$EnhancerByCGLIB$$c3066653,第一感觉就是跟jdk生成的那个代理类的名字风格差不多,把生成的类打印出来看
public class HelloConcrete$$EnhancerByCGLIB$$c3066653 extends HelloConcrete implements Factory { ... public final boolean equals(Object var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy); return var2 == null ? false : (Boolean)var2; } else { return super.equals(var1); } } public final String toString() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString(); } public final int hashCode() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy); return var1 == null ? 0 : ((Number)var1).intValue(); } else { return super.hashCode(); } } ... public final String sayHello(String var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (String)var10000.intercept(this, CGLIB$sayHello$0$Method, new Object[]{var1}, CGLIB$sayHello$0$Proxy) : super.sayHello(var1); } }
大致是这么个样子,其中省略了不少代码,当调用代理对象的sayHello()
方法时,首先会尝试转发给MethodInterceptor.intercept()
方法,如果没有MethodInterceptor
就执行父类的sayHello()
。它也实现了Object类的toString,hashCode和equals方法,而由于是通过继承实现,其他final的方法肯定就没法实现了。至于如何获取动态代理的生成类,jdk动态代理可以在生成代理类之前加上System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"),而CGLIB动态代理我是参考的https://blog.csdn.net/lzufeng/article/details/79322391。