app网站开发后台处理,我们做网站 出教材 办育心经,怎么做网站维护,东莞做网站建设关于JDK与cglib动态代理的使用不是本文关注的重点#xff0c;如有不清楚的同学可以查询相关资料进行了解。本文主要是要讲一下在面对方法存在嵌套调用时JDK与cglib动态代理的区别以及原因。
先看下测试代码#xff0c;注意下TestProxyJDKImpl的test1方法调用了test2方法即可…关于JDK与cglib动态代理的使用不是本文关注的重点如有不清楚的同学可以查询相关资料进行了解。本文主要是要讲一下在面对方法存在嵌套调用时JDK与cglib动态代理的区别以及原因。
先看下测试代码注意下TestProxyJDKImpl的test1方法调用了test2方法即可。 public class Test {static interface TestProxyJDK{void test1();void test2();}static class TestProxyJDKImp implements TestProxyJDK{Overridepublic void test1() {System.out.println(执行test1);test2();}Overridepublic void test2() {System.out.println(执行test2);}}public static void main(String[] args) throws NoSuchMethodException {//输出代理类System.getProperties().put(sun.misc.ProxyGenerator.saveGeneratedFiles, true);//创建JDK动态代理对象TestProxyJDKImp testProxyJDKImp new TestProxyJDKImp();TestProxyJDK testProxyJDK (TestProxyJDK) Proxy.newProxyInstance(Test.class.getClassLoader(), TestProxyJDKImp.class.getInterfaces(), new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String name method.getName();System.out.println(name 方法被拦截前执行方法);method.invoke(testProxyJDKImp, args);System.out.println(name 方法被拦截后执行方法);return null;}});//调用test1方法testProxyJDK.test1();//输出代理类System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, E:\\cglib);//创建cglib代理对象Enhancer enhancer new Enhancer();enhancer.setSuperclass(TestProxyJDKImp.class);enhancer.setCallback(new MethodInterceptor() {Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println(CGLIB拦截前);proxy.invokeSuper(obj,args);System.out.println(CGLIB拦截后);return null;}});TestProxyJDK testProxyCglib (TestProxyJDK) enhancer.create();//调用test1f方法testProxyCglib.test1();}}为了更好说明情况我们先把生成的代理类以文件的形式保存下来。对于JDK动态代理只需要在代码里添加如下一行代码即可。
//设置系统属性 1.8还是这种写法
System.getProperties().put(sun.misc.ProxyGenerator.saveGeneratedFiles, true); 生成类如下主要看下test1和test2方法的代码即可
final class $Proxy0 extends Proxy implements TestProxyJDK {private static Method m1;private static Method m2;private static Method m3;private static Method m4;private static Method m0;public $Proxy0(InvocationHandler var1) throws {super(var1);}public final boolean equals(Object var1) throws {try {// 这里的h就是我们创建的InvocationHandler对象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 test1() throws {try {super.h.invoke(this, m3, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final void test2() throws {try {super.h.invoke(this, m4, (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(com.xxx.xxx.Test$TestProxyJDK).getMethod(test1);m4 Class.forName(com.xxx.xxx.Test$TestProxyJDK).getMethod(test2);m0 Class.forName(java.lang.Object).getMethod(hashCode);} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}如果是cglib那么可以使用下面的方式输出代理类
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, your path);cglib生成的相关类不止一个这里就贴一下生成的代理类主要看下test1和test2方法的代码即可
public class Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c extends TestProxyJDKImp implements 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$test2$0$Method;private static final MethodProxy CGLIB$test2$0$Proxy;private static final Object[] CGLIB$emptyArgs;private static final Method CGLIB$test1$1$Method;private static final MethodProxy CGLIB$test1$1$Proxy;private static final Method CGLIB$finalize$2$Method;private static final MethodProxy CGLIB$finalize$2$Proxy;private static final Method CGLIB$equals$3$Method;private static final MethodProxy CGLIB$equals$3$Proxy;private static final Method CGLIB$toString$4$Method;private static final MethodProxy CGLIB$toString$4$Proxy;private static final Method CGLIB$hashCode$5$Method;private static final MethodProxy CGLIB$hashCode$5$Proxy;private static final Method CGLIB$clone$6$Method;private static final MethodProxy CGLIB$clone$6$Proxy;static void CGLIB$STATICHOOK1() {CGLIB$THREAD_CALLBACKS new ThreadLocal();CGLIB$emptyArgs new Object[0];Class var0 Class.forName(com.xxx.xxx.Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c);Class var1;Method[] var10000 ReflectUtils.findMethods(new String[]{finalize, ()V, equals, (Ljava/lang/Object;)Z, toString, ()Ljava/lang/String;, hashCode, ()I, clone, ()Ljava/lang/Object;}, (var1 Class.forName(java.lang.Object)).getDeclaredMethods());CGLIB$finalize$2$Method var10000[0];CGLIB$finalize$2$Proxy MethodProxy.create(var1, var0, ()V, finalize, CGLIB$finalize$2);CGLIB$equals$3$Method var10000[1];CGLIB$equals$3$Proxy MethodProxy.create(var1, var0, (Ljava/lang/Object;)Z, equals, CGLIB$equals$3);CGLIB$toString$4$Method var10000[2];CGLIB$toString$4$Proxy MethodProxy.create(var1, var0, ()Ljava/lang/String;, toString, CGLIB$toString$4);CGLIB$hashCode$5$Method var10000[3];CGLIB$hashCode$5$Proxy MethodProxy.create(var1, var0, ()I, hashCode, CGLIB$hashCode$5);CGLIB$clone$6$Method var10000[4];CGLIB$clone$6$Proxy MethodProxy.create(var1, var0, ()Ljava/lang/Object;, clone, CGLIB$clone$6);var10000 ReflectUtils.findMethods(new String[]{test2, ()V, test1, ()V}, (var1 Class.forName(com.xxx.xxx.Test$TestProxyJDKImp)).getDeclaredMethods());CGLIB$test2$0$Method var10000[0];CGLIB$test2$0$Proxy MethodProxy.create(var1, var0, ()V, test2, CGLIB$test2$0);CGLIB$test1$1$Method var10000[1];CGLIB$test1$1$Proxy MethodProxy.create(var1, var0, ()V, test1, CGLIB$test1$1);}final void CGLIB$test2$0() {super.test2();}public final void test2() {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$test2$0$Method, CGLIB$emptyArgs, CGLIB$test2$0$Proxy);} else {super.test2();}}final void CGLIB$test1$1() {super.test1();}public final void test1() {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$test1$1$Method, CGLIB$emptyArgs, CGLIB$test1$1$Proxy);} else {super.test1();}}final void CGLIB$finalize$2() throws Throwable {super.finalize();}protected final void finalize() throws Throwable {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$finalize$2$Method, CGLIB$emptyArgs, CGLIB$finalize$2$Proxy);} else {super.finalize();}}final boolean CGLIB$equals$3(Object var1) {return super.equals(var1);}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$3$Method, new Object[]{var1}, CGLIB$equals$3$Proxy);return var2 null ? false : (Boolean)var2;} else {return super.equals(var1);}}final String CGLIB$toString$4() {return super.toString();}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$4$Method, CGLIB$emptyArgs, CGLIB$toString$4$Proxy) : super.toString();}final int CGLIB$hashCode$5() {return super.hashCode();}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$5$Method, CGLIB$emptyArgs, CGLIB$hashCode$5$Proxy);return var1 null ? 0 : ((Number)var1).intValue();} else {return super.hashCode();}}final Object CGLIB$clone$6() throws CloneNotSupportedException {return super.clone();}protected final Object clone() throws CloneNotSupportedException {MethodInterceptor var10000 this.CGLIB$CALLBACK_0;if (var10000 null) {CGLIB$BIND_CALLBACKS(this);var10000 this.CGLIB$CALLBACK_0;}return var10000 ! null ? var10000.intercept(this, CGLIB$clone$6$Method, CGLIB$emptyArgs, CGLIB$clone$6$Proxy) : super.clone();}public static MethodProxy CGLIB$findMethodProxy(Signature var0) {String var10000 var0.toString();switch(var10000.hashCode()) {case -1574182249:if (var10000.equals(finalize()V)) {return CGLIB$finalize$2$Proxy;}break;case -1147892426:if (var10000.equals(test1()V)) {return CGLIB$test1$1$Proxy;}break;case -1147862635:if (var10000.equals(test2()V)) {return CGLIB$test2$0$Proxy;}break;case -508378822:if (var10000.equals(clone()Ljava/lang/Object;)) {return CGLIB$clone$6$Proxy;}break;case 1826985398:if (var10000.equals(equals(Ljava/lang/Object;)Z)) {return CGLIB$equals$3$Proxy;}break;case 1913648695:if (var10000.equals(toString()Ljava/lang/String;)) {return CGLIB$toString$4$Proxy;}break;case 1984935277:if (var10000.equals(hashCode()I)) {return CGLIB$hashCode$5$Proxy;}}return null;}public Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c() {CGLIB$BIND_CALLBACKS(this);}public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {CGLIB$THREAD_CALLBACKS.set(var0);}public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {CGLIB$STATIC_CALLBACKS var0;}private static final void CGLIB$BIND_CALLBACKS(Object var0) {Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c var1 (Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c)var0;if (!var1.CGLIB$BOUND) {var1.CGLIB$BOUND true;Object var10000 CGLIB$THREAD_CALLBACKS.get();if (var10000 null) {var10000 CGLIB$STATIC_CALLBACKS;if (var10000 null) {return;}}var1.CGLIB$CALLBACK_0 (MethodInterceptor)((Callback[])var10000)[0];}}public Object newInstance(Callback[] var1) {CGLIB$SET_THREAD_CALLBACKS(var1);Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c var10000 new Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;}public Object newInstance(Callback var1) {CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c var10000 new Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;}public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {CGLIB$SET_THREAD_CALLBACKS(var3);Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c var10000 new Test$TestProxyJDKImp$$EnhancerByCGLIB$$62be832c;switch(var1.length) {case 0:var10000.init();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;default:throw new IllegalArgumentException(Constructor not found);}}public Callback getCallback(int var1) {CGLIB$BIND_CALLBACKS(this);MethodInterceptor var10000;switch(var1) {case 0:var10000 this.CGLIB$CALLBACK_0;break;default:var10000 null;}return var10000;}public void setCallback(int var1, Callback var2) {switch(var1) {case 0:this.CGLIB$CALLBACK_0 (MethodInterceptor)var2;default:}}public Callback[] getCallbacks() {CGLIB$BIND_CALLBACKS(this);return new Callback[]{this.CGLIB$CALLBACK_0};}public void setCallbacks(Callback[] var1) {this.CGLIB$CALLBACK_0 (MethodInterceptor)var1[0];}static {CGLIB$STATICHOOK1();}
}在方法1中调用方法2使用JDK动态代理和使用cglib动态代理有什么区别
执行上面测试代码的main方法打印结果如下:
test1方法被拦截前执行方法
执行test1
执行test2
test1方法被拦截后执行方法CGLIB拦截前
执行test1
CGLIB拦截前
执行test2
CGLIB拦截后
CGLIB拦截后可以看到使用JDK代理的时候在test1方法里调用test2时test2方法并未被拦截调用的还是被代理类的test2方法。使用cglib代理的时候在test1方法里调用test2时test2也被拦截调用的是生成的代理类的test2方法。
这是为什么呢
回到我们生成的代理类使用JDK代理的时候调用test1方法最终执行的是InvocationHandler的invoke方法.
super.h.invoke(this, m3, (Object[])null);在invoke方法里调用被代理的test1方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String name method.getName();System.out.println(name 方法被拦截前执行方法);method.invoke(testProxyJDKImp, args);System.out.println(name 方法被拦截后执行方法);return null;}注意这里使用 method.invoke(testProxyJDKImp, args)使用的是被代理对象那么在test1方法里调用this.test2时这个this自然就是被代理对象那么test2走的就是原始的方法
而使用cglib代理的时候调用test1方法最终执行的是 public final void test1() {MethodInterceptor var10000 this.CGLIB$CALLBACK_0;if (var10000 null) {CGLIB$BIND_CALLBACKS(this);var10000 this.CGLIB$CALLBACK_0;}if (var10000 ! null) {//这个this就是下面的obj是代理对象var10000.intercept(this, CGLIB$test1$1$Method, CGLIB$emptyArgs, CGLIB$test1$1$Proxy);} else {super.test1();}}也就是我们实现的MethodInterceptor的intercept方法里 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println(CGLIB拦截前);proxy.invokeSuper(obj,args);System.out.println(CGLIB拦截后);return null;}注意cglib代理时我们从头到尾并不需要被代理类的对象这里的obj是代理对象那么自然在调用test1方法时它里面的this.test2方法里的this就是代理对象自然执行的是被代理后的test2方法。
说到这里你有没有想起Transactional的一种失效的使用场景呢其实道理都是一样的。