基于JDK的动态代理:JDK内置,无需依赖第三方jar包,比较常见的是这种
基于cglib的动态代理:需要引入net.sf.cglib第三方jar包:http://www.java2s.com/Code/Jar/c/Downloadcglibjar.htm
Spring框架也内置了该jar包
构建一个代理类,实现invocationHandler接口,此代理类创建的时候未与任何的被代理类绑定,动态代理即此体现;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @author qinzhen * @create 2020/10/6 12:21 */ public class JdkDynamicProxy implements InvocationHandler { private Object target; public JdkDynamicProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("proxy says this is the before things"); Object result = method.invoke(target, args); System.out.println("proxy says this is the after things"); return result; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } }被代理类,必须继承一个接口
/** * @author qinzhen * @create 2020/10/6 12:18 */ public interface HelloService { void hello(); } public class HelloServiceImpl implements HelloService { @Override public void hello() { System.out.println("hello, this is hello service implement"); } }将代理类与被代理对象绑定,创建一个新的代理对象instance;
public class testJdkProxy { public static void main(String[] args) { System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(new HelloServiceImpl()); HelloService instance = (HelloService) Proxy.newProxyInstance(jdkDynamicProxy.getClass().getClassLoader(), jdkDynamicProxy.getTarget().getClass().getInterfaces(), jdkDynamicProxy); instance.hello(); } }重点在于Proxy.newProxyInstance这个方法,这个方法实现了将jdkDynamicProxy和HelloServiceImpl动态绑定,并且通过二进制流的方式拼接成了一个新的代理类对象$Proxy0.class。
System.setProperty(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”) 这行代码就是将$Proxy0.class对象显示在$classpath: com/sun/proxy路径下,$Proxy0.class的源码如下:
public final class $Proxy0 extends Proxy implements HelloService { private static Method m1; private static Method m3; private static Method m2; 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 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); } } .............. // 下面还有重写了一系列的Object的方法可以看出两个结论:
继承了HelloService接口,然后依赖于InvocationHandler类来实现与被代理类之间的动态绑定,继承接口很重要;重写了Object类的所有方法,如toString(),equals()等构建代理类,实现MethodInterceptor接口
/** * @author qinzhen * @create 2020/10/7 8:31 */ public class CglibDynamicProxy implements MethodInterceptor { private Object target; public CglibDynamicProxy(Object target) { this.target = target; } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("这是动态代理前的输出...."); Object result = method.invoke(target, objects); System.out.println("这是动态代理后的输出...."); return result; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } }将代理类与被代理对象绑定
/** * @author qinzhen * @create 2020/10/7 8:46 */ public class testCglibDynamicProxy { public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "true"); CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy(new HelloServiceImpl()); Enhancer enhancer = new Enhancer(); enhancer.setInterfaces(cglibDynamicProxy.getTarget().getClass().getInterfaces()); // enhancer.setSuperclass(cglibDynamicProxy.getTarget().getClass()); enhancer.setCallback(cglibDynamicProxy); // HelloServiceImpl instance = (HelloServiceImpl) enhancer.create(); HelloService instance = (HelloService) enhancer.create(); instance.hello(); } }同样,cglib动态代理也会通过二进制流的方式将被代理类拼接成一个代理对象,代理对象代码如下:
public class HelloService$$EnhancerByCGLIB$$9d4f0b4 implements HelloService, Factory { private boolean CGLIB$BOUND; private static final ThreadLocal CGLIB$THREAD_CALLBACKS; private static final Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; private static final Method CGLIB$finalize$0$Method; private static final MethodProxy CGLIB$finalize$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$equals$1$Method; private static final MethodProxy CGLIB$equals$1$Proxy; private static final Method CGLIB$toString$2$Method; private static final MethodProxy CGLIB$toString$2$Proxy; private static final Method CGLIB$hashCode$3$Method; private static final MethodProxy CGLIB$hashCode$3$Proxy; private static final Method CGLIB$clone$4$Method; private static final MethodProxy CGLIB$clone$4$Proxy; private static final Method CGLIB$hello$5$Method; private static final MethodProxy CGLIB$hello$5$Proxy; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); Class var0; ClassLoader var10000 = (var0 = Class.forName("proxy.cglibProxy.po.HelloService$$EnhancerByCGLIB$$9d4f0b4")).getClassLoader(); CGLIB$emptyArgs = new Object[0]; CGLIB$finalize$0$Proxy = MethodProxy.create(var10000, (CGLIB$finalize$0$Method = Class.forName("java.lang.Object").getDeclaredMethod("finalize")).getDeclaringClass(), var0, "()V", "finalize", "CGLIB$finalize$0"); CGLIB$equals$1$Proxy = MethodProxy.create(var10000, (CGLIB$equals$1$Method = Class.forName("java.lang.Object").getDeclaredMethod("equals", Class.forName("java.lang.Object"))).getDeclaringClass(), var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1"); CGLIB$toString$2$Proxy = MethodProxy.create(var10000, (CGLIB$toString$2$Method = Class.forName("java.lang.Object").getDeclaredMethod("toString")).getDeclaringClass(), var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2"); CGLIB$hashCode$3$Proxy = MethodProxy.create(var10000, (CGLIB$hashCode$3$Method = Class.forName("java.lang.Object").getDeclaredMethod("hashCode")).getDeclaringClass(), var0, "()I", "hashCode", "CGLIB$hashCode$3"); CGLIB$clone$4$Proxy = MethodProxy.create(var10000, (CGLIB$clone$4$Method = Class.forName("java.lang.Object").getDeclaredMethod("clone")).getDeclaringClass(), var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4"); CGLIB$hello$5$Proxy = MethodProxy.create(var10000, (CGLIB$hello$5$Method = Class.forName("proxy.cglibProxy.po.HelloService").getDeclaredMethod("hello")).getDeclaringClass(), var0, "()V", "hello", "CGLIB$hello$5"); } final void CGLIB$finalize$0() throws Throwable { super.finalize(); } 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 void hello() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { var10000.intercept(this, CGLIB$hello$5$Method, CGLIB$emptyArgs, CGLIB$hello$5$Proxy); } else { super.hello(); } }可以看到,这个代理对象也是通过实现HelloService接口来与被代理类动态绑定的,并且也重写了Object类下的方法
这个代理对象将代理类和被代理类绑定在一起,即重新实现了被代理类的方法,并注入代理类和被代理类
JDK代理类和cglib代理类都需要继承一个预设的接口,前者是InvocationHandler,后者是MethodInterceptorJDK动态代理的代理对象是接口,不是类,所以采用JDK动态代理的被代理类必须要继承一个接口,否则会报异常。
从$Proxy0的代码可以看出,这样做的原因是,JDK动态代理就是要通过继承一个接口来实现代理类与被代理类之间的绑定操作。笔者理解是,当时设计该模块的时候是为了基于接口编程,所以才会通过接口实现绑定,这个后来也被很多人诟病。
cglib代理就弥补了这个问题,既可以通过接口来实现绑定,也可以通过继承来实现绑定,因此被代理类没有强制要实现一个接口,cglib会根据其变量的非空来自动生成对应的绑定类型的代理对象,如下:
这里采用的是实现接口的方式:
enhancer.setInterfaces(cglibProxy.getTarget().getClass().getInterfaces());生成的代理对象如下:
public class HelloService$$EnhancerByCGLIB$$9d4f0b4 implements HelloService, Factory { ..... }这里采用的是继承的方式:
enhancer.setSuperclass(cglibDynamicProxy.getTarget().getClass());生成的代理对象如下:
public class HelloServiceImpl$$EnhancerByCGLIB$$5e85687 extends HelloServiceImpl implements Factory { ..... } 可见,cglib的代理方式更加自由。