本文共 44312 字,大约阅读时间需要 147 分钟。
Cglib代理原理解密
cglib与动态代理功能类似,都是为了做方法拦截的,从而增强方法功能,本文讲解cglib的原理
我有一个CglibDemo类,也就是main方法的测试类, 他有一个属性name和他的get set方法
import net.sf.cglib.core.DebuggingClassWriter;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/** * @author hh * @date 2020/9/29 */public class CglibDemo { public static void main(String[] args) throws Exception{ System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "c:\\classes"); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(CglibDemo.class); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before..."); Object result = proxy.invokeSuper(obj, args); System.out.println("after ..."); return result; } }); CglibDemo cglibProxy = (CglibDemo) enhancer.create(); cglibProxy.getName(); } private String name; public String getName() { System.out.println("get name..."); return name; } public void setName(String name) { System.out.println("set name..."); this.name = name; }}
我想在setName和getName方法被调用之前打印"before" 之后打印"after", 运行以上main方法成功打印:
before...get name...after ...
cglib代理一共生成了三个class,使用的是asm框架在内存中动态生成的,他们分别是:
CglibDemo$$EnhancerByCGLIB$$1a76a66CglibDemo$$EnhancerByCGLIB$$1a76a66$$FastClassByCGLIB$$ea5d0752CglibDemo$$FastClassByCGLIB$$4320d206
1.先讲解 CglibDemo$$EnhancerByCGLIB$$1a76a66
- 这个类是我们
CglibDemo cglibProxy = (CglibDemo) enhancer.create();
获得的代理类,他不是FastClass类 - 注意他的名字中没有
FastClass
字眼 - 因为
enhancer.setSuperclass(CglibDemo.class)
,所以他是CglibDemo
的子类,而且名字中也带有CglibDemo
字眼 - 这个类的内容如下:
/** * 这个类是从内存中使用hsdb工具弄下来,再使用idea反编译,然后手动修改其中的编译错误而来的 * * 这个类是代理类,是cglib生成的CglibDemo子类 */import lombok.SneakyThrows;import net.sf.cglib.core.ReflectUtils;import net.sf.cglib.core.Signature;import net.sf.cglib.proxy.Callback;import net.sf.cglib.proxy.Factory;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CglibDemo$$EnhancerByCGLIB$$1a76a66 extends CglibDemo implements Factory { private boolean CGLIB$BOUND; public static Object CGLIB$FACTORY_DATA; private static ThreadLocal CGLIB$THREAD_CALLBACKS; private static Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; private static Object CGLIB$CALLBACK_FILTER; private static Method CGLIB$getName$0$Method; private static MethodProxy CGLIB$getName$0$Proxy; private static Object[] CGLIB$emptyArgs; private static Method CGLIB$setName$1$Method; private static MethodProxy CGLIB$setName$1$Proxy; private static Method CGLIB$equals$2$Method; private static MethodProxy CGLIB$equals$2$Proxy; private static Method CGLIB$toString$3$Method; private static MethodProxy CGLIB$toString$3$Proxy; private static Method CGLIB$hashCode$4$Method; private static MethodProxy CGLIB$hashCode$4$Proxy; private static Method CGLIB$clone$5$Method; private static MethodProxy CGLIB$clone$5$Proxy; public CglibDemo$$EnhancerByCGLIB$$1a76a66() { CGLIB$BIND_CALLBACKS(this); } static { CGLIB$STATICHOOK1(); } @SneakyThrows 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$2$Method, new Object[]{ var1}, CGLIB$equals$2$Proxy); return var2 == null ? false : (Boolean)var2; } else { return super.equals(var1); } } @SneakyThrows 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$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy) : super.toString(); } @SneakyThrows 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$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy); return var1 == null ? 0 : ((Number)var1).intValue(); } else { return super.hashCode(); } } @SneakyThrows 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$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone(); } @SneakyThrows public final String getName() { 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$getName$0$Method, CGLIB$emptyArgs, CGLIB$getName$0$Proxy) : super.getName(); } public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { CGLIB$SET_THREAD_CALLBACKS(var3); CglibDemo$$EnhancerByCGLIB$$1a76a66 var10000 = new CglibDemo$$EnhancerByCGLIB$$1a76a66(); switch(var1.length) { case 0: // var10000.(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; default: throw new IllegalArgumentException("Constructor not found"); } } public Object newInstance(Callback var1) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{ var1}); CglibDemo$$EnhancerByCGLIB$$1a76a66 var10000 = new CglibDemo$$EnhancerByCGLIB$$1a76a66(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Callback[] var1) { CGLIB$SET_THREAD_CALLBACKS(var1); CglibDemo$$EnhancerByCGLIB$$1a76a66 var10000 = new CglibDemo$$EnhancerByCGLIB$$1a76a66(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } @SneakyThrows public final void setName(String var1) { 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$setName$1$Method, new Object[]{ var1}, CGLIB$setName$1$Proxy); } else { super.setName(var1); } } public void setCallbacks(Callback[] var1) { this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0]; } 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 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 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; } public static MethodProxy CGLIB$findMethodProxy(Signature var0) { String var10000 = var0.toString(); switch(var10000.hashCode()) { case -1184972270: if (var10000.equals("setName(Ljava/lang/String;)V")) { return CGLIB$setName$1$Proxy; } break; case -508378822: if (var10000.equals("clone()Ljava/lang/Object;")) { return CGLIB$clone$5$Proxy; } break; case 1218144844: if (var10000.equals("getName()Ljava/lang/String;")) { return CGLIB$getName$0$Proxy; } break; case 1826985398: if (var10000.equals("equals(Ljava/lang/Object;)Z")) { return CGLIB$equals$2$Proxy; } break; case 1913648695: if (var10000.equals("toString()Ljava/lang/String;")) { return CGLIB$toString$3$Proxy; } break; case 1984935277: if (var10000.equals("hashCode()I")) { return CGLIB$hashCode$4$Proxy; } } return null; } @SneakyThrows static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class var0 = Class.forName("hh.proxy.cglib.CglibDemo$$EnhancerByCGLIB$$1a76a66"); Class var1; Method[] var10000 = ReflectUtils.findMethods(new String[]{ "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods()); CGLIB$equals$2$Method = var10000[0]; CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2"); CGLIB$toString$3$Method = var10000[1]; CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3"); CGLIB$hashCode$4$Method = var10000[2]; CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4"); CGLIB$clone$5$Method = var10000[3]; CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5"); var10000 = ReflectUtils.findMethods(new String[]{ "getName", "()Ljava/lang/String;", "setName", "(Ljava/lang/String;)V"}, (var1 = Class.forName("hh.proxy.cglib.CglibDemo")).getDeclaredMethods()); CGLIB$getName$0$Method = var10000[0]; CGLIB$getName$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "getName", "CGLIB$getName$0"); CGLIB$setName$1$Method = var10000[1]; CGLIB$setName$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "setName", "CGLIB$setName$1"); } private static final void CGLIB$BIND_CALLBACKS(Object var0) { CglibDemo$$EnhancerByCGLIB$$1a76a66 var1 = (CglibDemo$$EnhancerByCGLIB$$1a76a66)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]; } } final int CGLIB$hashCode$4() { return super.hashCode(); } final String CGLIB$toString$3() { return super.toString(); } final String CGLIB$getName$0() { return super.getName(); } final boolean CGLIB$equals$2(Object var1) { return super.equals(var1); } final void CGLIB$setName$1(String var1) { super.setName(var1); } final Object CGLIB$clone$5() throws CloneNotSupportedException { return super.clone(); }}
2. 类CglibDemo$$FastClassByCGLIB$$4320d206
- 这个类是一个FastClass类
- 注意他的名字中有
FastClass
字眼 - 他是一个FastClass1类, 至于为什么说他是
1
, 待会解密 - 这个类的内容如下:
/** * 这个类是从内存中使用hsdb工具弄下来,再使用idea反编译,然后手动修改其中的编译错误而来的 * * 这个类是一个FastClass,而且他是FastClass1 * @author hh * @date 2020/9/29 */import net.sf.cglib.core.Signature;import net.sf.cglib.reflect.FastClass;import java.lang.reflect.InvocationTargetException;public class CglibDemo$$FastClassByCGLIB$$4320d206 extends FastClass { public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { CglibDemo var10000 = (CglibDemo)var2; int var10001 = var1; try { switch(var10001) { case 0: CglibDemo.main((String[])var3[0]); return null; case 1: return var10000.getName(); case 2: var10000.setName((String)var3[0]); return null; case 3: return new Boolean(var10000.equals(var3[0])); case 4: return var10000.toString(); case 5: return new Integer(var10000.hashCode()); } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } public CglibDemo$$FastClassByCGLIB$$4320d206(Class var1) { super(var1); } public Object newInstance(int var1, Object[] var2) throws InvocationTargetException { CglibDemo var10000 = new CglibDemo(); CglibDemo var10001 = var10000; int var10002 = var1; try { switch(var10002) { case 0: // var10001.(); return var10000; } } catch (Throwable var3) { throw new InvocationTargetException(var3); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } public int getIndex(Class[] var1) { switch(var1.length) { case 0: return 0; default: return -1; } } public int getIndex(String var1, Class[] var2) { switch(var1.hashCode()) { case -1776922004: if (var1.equals("toString")) { switch(var2.length) { case 0: return 4; } } break; case -1295482945: if (var1.equals("equals")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.Object")) { return 3; } } } break; case -75308287: if (var1.equals("getName")) { switch(var2.length) { case 0: return 1; } } break; case 3343801: if (var1.equals("main")) { switch(var2.length) { case 1: if (var2[0].getName().equals("[Ljava.lang.String;")) { return 0; } } } break; case 147696667: if (var1.equals("hashCode")) { switch(var2.length) { case 0: return 5; } } break; case 1984801293: if (var1.equals("setName")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.String")) { return 2; } } } } return -1; } public int getIndex(Signature var1) { String var10000 = var1.toString(); switch(var10000.hashCode()) { case -1184972270: if (var10000.equals("setName(Ljava/lang/String;)V")) { return 2; } break; case 1218144844: if (var10000.equals("getName()Ljava/lang/String;")) { return 1; } break; case 1341835395: if (var10000.equals("main([Ljava/lang/String;)V")) { return 0; } break; case 1826985398: if (var10000.equals("equals(Ljava/lang/Object;)Z")) { return 3; } break; case 1913648695: if (var10000.equals("toString()Ljava/lang/String;")) { return 4; } break; case 1984935277: if (var10000.equals("hashCode()I")) { return 5; } } return -1; } public int getMaxIndex() { return 5; }}
3. 类CglibDemo$$EnhancerByCGLIB$$1a76a66$$FastClassByCGLIB$$ea5d0752
- 这个类是一个的名字有点长, 他是一个FastClass类
- 注意他的名字中有
FastClass
字眼 - 他是一个FastClass2类, 至于为什么说他是2, 待会解密
- 这个类的内容如下:
/** * 这个类是从内存中使用hsdb工具弄下来,再使用idea反编译,然后手动修改其中的编译错误而来的 * * 这个类是一个FastClass,而且他是FastClass2 * @author hh * @date 2020/9/29 */import net.sf.cglib.core.Signature;import net.sf.cglib.proxy.Callback;import net.sf.cglib.reflect.FastClass;import java.lang.reflect.InvocationTargetException;public class CglibDemo$$EnhancerByCGLIB$$1a76a66$$FastClassByCGLIB$$ea5d0752 extends FastClass { public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { CglibDemo$$EnhancerByCGLIB$$1a76a66 var10000 = (CglibDemo$$EnhancerByCGLIB$$1a76a66)var2; int var10001 = var1; try { switch(var10001) { case 0: return new Boolean(var10000.equals(var3[0])); case 1: return var10000.toString(); case 2: return new Integer(var10000.hashCode()); case 3: return var10000.clone(); case 4: return var10000.getName(); case 5: return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]); case 6: return var10000.newInstance((Callback)var3[0]); case 7: return var10000.newInstance((Callback[])var3[0]); case 8: var10000.setName((String)var3[0]); return null; case 9: var10000.setCallbacks((Callback[])var3[0]); return null; case 10: var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]); return null; case 11: return var10000.getCallbacks(); case 12: return var10000.getCallback(((Number)var3[0]).intValue()); case 13: CglibDemo$$EnhancerByCGLIB$$1a76a66.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]); return null; case 14: CglibDemo$$EnhancerByCGLIB$$1a76a66.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]); return null; case 15: return CglibDemo$$EnhancerByCGLIB$$1a76a66.CGLIB$findMethodProxy((Signature)var3[0]); case 16: CglibDemo$$EnhancerByCGLIB$$1a76a66.CGLIB$STATICHOOK1(); return null; case 17: return new Integer(var10000.CGLIB$hashCode$4()); case 18: return var10000.CGLIB$toString$3(); case 19: return var10000.CGLIB$getName$0(); case 20: return new Boolean(var10000.CGLIB$equals$2(var3[0])); case 21: var10000.CGLIB$setName$1((String)var3[0]); return null; case 22: return var10000.CGLIB$clone$5(); case 23: CglibDemo.main((String[])var3[0]); return null; } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } public CglibDemo$$EnhancerByCGLIB$$1a76a66$$FastClassByCGLIB$$ea5d0752(Class var1) { super(var1); } public Object newInstance(int var1, Object[] var2) throws InvocationTargetException { CglibDemo$$EnhancerByCGLIB$$1a76a66 var10000 = new CglibDemo$$EnhancerByCGLIB$$1a76a66(); CglibDemo$$EnhancerByCGLIB$$1a76a66 var10001 = var10000; int var10002 = var1; try { switch(var10002) { case 0: // var10001.(); return var10000; } } catch (Throwable var3) { throw new InvocationTargetException(var3); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } public int getIndex(Class[] var1) { switch(var1.length) { case 0: return 0; default: return -1; } } public int getIndex(String var1, Class[] var2) { switch(var1.hashCode()) { case -1776922004: if (var1.equals("toString")) { switch(var2.length) { case 0: return 1; } } break; case -1295482945: if (var1.equals("equals")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.Object")) { return 0; } } } break; case -1053468136: if (var1.equals("getCallbacks")) { switch(var2.length) { case 0: return 11; } } break; case -124978608: if (var1.equals("CGLIB$equals$2")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.Object")) { return 20; } } } break; case -75308287: if (var1.equals("getName")) { switch(var2.length) { case 0: return 4; } } break; case -60403779: if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) { switch(var2.length) { case 1: if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) { return 14; } } } break; case -29025554: if (var1.equals("CGLIB$hashCode$4")) { switch(var2.length) { case 0: return 17; } } break; case 3343801: if (var1.equals("main")) { switch(var2.length) { case 1: if (var2[0].getName().equals("[Ljava.lang.String;")) { return 23; } } } break; case 5451255: if (var1.equals("CGLIB$setName$1")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.String")) { return 21; } } } break; case 85179481: if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) { switch(var2.length) { case 1: if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) { return 13; } } } break; case 94756189: if (var1.equals("clone")) { switch(var2.length) { case 0: return 3; } } break; case 147696667: if (var1.equals("hashCode")) { switch(var2.length) { case 0: return 2; } } break; case 161998109: if (var1.equals("CGLIB$STATICHOOK1")) { switch(var2.length) { case 0: return 16; } } break; case 220068330: if (var1.equals("CGLIB$getName$0")) { switch(var2.length) { case 0: return 19; } } break; case 495524492: if (var1.equals("setCallbacks")) { switch(var2.length) { case 1: if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) { return 9; } } } break; case 1154623345: if (var1.equals("CGLIB$findMethodProxy")) { switch(var2.length) { case 1: if (var2[0].getName().equals("net.sf.cglib.core.Signature")) { return 15; } } } break; case 1543336190: if (var1.equals("CGLIB$toString$3")) { switch(var2.length) { case 0: return 18; } } break; case 1811874389: if (var1.equals("newInstance")) { switch(var2.length) { case 1: String var10001 = var2[0].getName(); switch(var10001.hashCode()) { case -845341380: if (var10001.equals("net.sf.cglib.proxy.Callback")) { return 6; } break; case 1730110032: if (var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) { return 7; } } case 2: default: break; case 3: if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) { return 5; } } } break; case 1817099975: if (var1.equals("setCallback")) { switch(var2.length) { case 2: if (var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) { return 10; } } } break; case 1905679803: if (var1.equals("getCallback")) { switch(var2.length) { case 1: if (var2[0].getName().equals("int")) { return 12; } } } break; case 1951977611: if (var1.equals("CGLIB$clone$5")) { switch(var2.length) { case 0: return 22; } } break; case 1984801293: if (var1.equals("setName")) { switch(var2.length) { case 1: if (var2[0].getName().equals("java.lang.String")) { return 8; } } } } return -1; } public int getIndex(Signature var1) { String var10000 = var1.toString(); switch(var10000.hashCode()) { case -2055565910: if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) { return 13; } break; case -1457535688: if (var10000.equals("CGLIB$STATICHOOK1()V")) { return 16; } break; case -1411812934: if (var10000.equals("CGLIB$hashCode$4()I")) { return 17; } break; case -1184972270: if (var10000.equals("setName(Ljava/lang/String;)V")) { return 8; } break; case -894172689: if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) { return 6; } break; case -623122092: if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) { return 15; } break; case -508378822: if (var10000.equals("clone()Ljava/lang/Object;")) { return 3; } break; case -419626537: if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) { return 9; } break; case 374345669: if (var10000.equals("CGLIB$equals$2(Ljava/lang/Object;)Z")) { return 20; } break; case 453440181: if (var10000.equals("CGLIB$getName$0()Ljava/lang/String;")) { return 19; } break; case 560567118: if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) { return 10; } break; case 811063227: if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) { return 5; } break; case 973717575: if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) { return 11; } break; case 1218144844: if (var10000.equals("getName()Ljava/lang/String;")) { return 4; } break; case 1221173700: if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) { return 7; } break; case 1230699260: if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) { return 12; } break; case 1341835395: if (var10000.equals("main([Ljava/lang/String;)V")) { return 23; } break; case 1517819849: if (var10000.equals("CGLIB$toString$3()Ljava/lang/String;")) { return 18; } break; case 1584330438: if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) { return 14; } break; case 1826985398: if (var10000.equals("equals(Ljava/lang/Object;)Z")) { return 0; } break; case 1913648695: if (var10000.equals("toString()Ljava/lang/String;")) { return 1; } break; case 1984935277: if (var10000.equals("hashCode()I")) { return 2; } break; case 2011844968: if (var10000.equals("CGLIB$clone$5()Ljava/lang/Object;")) { return 22; } break; case 2033562728: if (var10000.equals("CGLIB$setName$1(Ljava/lang/String;)V")) { return 21; } } return -1; } public int getMaxIndex() { return 23; }}
Cglib代理生成的所有类都介绍了,下面介绍cglibProxy.getName();
都做了什么
注意这个getName我希望他之前打印before,之后打印after,所以他是一个代理方法,被我增强了
CglibDemo cglibProxy = (CglibDemo) enhancer.create();
得到的是 CglibDemo$$EnhancerByCGLIB$$1a76a66
(类名没有FastClass哦),我调用的是getName()方法,那么这个代理类一定也有getName()方法: @SneakyThrows public final String getName() { 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$getName$0$Method, CGLIB$emptyArgs, CGLIB$getName$0$Proxy) : super.getName(); }
他实际调用的是拦截器的intercept方法,拦截器就是:
enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before..."); Object result = proxy.invokeSuper(obj, args); System.out.println("after ..."); return result; } });
好吧我们把它贴到一起做一个对比
var10000.intercept(this, CGLIB$getName$0$Method, CGLIB$emptyArgs, CGLIB$getName$0$Proxy) @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { }
然后到了拦截器的intercept方法,我调用了proxy.invokeSuper(obj, args);
到这里, 就必须说说之前我为什么说一个FastClass是1,另一个FastClass是2, 看invokeSuper
源码:
public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } }
其中, FastClassInfo就包含了两个FastClass, 他的两个属性,f1=CglibDemo$$FastClassByCGLIB$$4320d206
和f2=CglibDemo$$EnhancerByCGLIB$$1a76a66$$FastClassByCGLIB$$ea5d0752
invokeSuper
他用的是FastClass2,也就是f2, (invoke使用的是FastClass1也就是f1), Object参数还是代理对象啊, 当然还有一个属性,fci.i2, 这个i2就是index2的意思,就是方法索引, 这个方法索引什么意思呢, 继续往下看. 现在调用的是FastClass2的invoke,我们看看这个invoke里面写的是啥: public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { CglibDemo$$EnhancerByCGLIB$$1a76a66 var10000 = (CglibDemo$$EnhancerByCGLIB$$1a76a66)var2; int var10001 = var1; try { switch(var10001) { case 0: return new Boolean(var10000.equals(var3[0])); case 1: return var10000.toString(); case 2: return new Integer(var10000.hashCode()); case 3: return var10000.clone(); case 4: return var10000.getName(); case 5: return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]); case 6: return var10000.newInstance((Callback)var3[0]); case 7: return var10000.newInstance((Callback[])var3[0]); case 8: var10000.setName((String)var3[0]); return null; case 9: var10000.setCallbacks((Callback[])var3[0]); return null; case 10: var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]); return null; case 11: return var10000.getCallbacks(); case 12: return var10000.getCallback(((Number)var3[0]).intValue()); case 13: CglibDemo$$EnhancerByCGLIB$$1a76a66.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]); return null; case 14: CglibDemo$$EnhancerByCGLIB$$1a76a66.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]); return null; case 15: return CglibDemo$$EnhancerByCGLIB$$1a76a66.CGLIB$findMethodProxy((Signature)var3[0]); case 16: CglibDemo$$EnhancerByCGLIB$$1a76a66.CGLIB$STATICHOOK1(); return null; case 17: return new Integer(var10000.CGLIB$hashCode$4()); case 18: return var10000.CGLIB$toString$3(); case 19: return var10000.CGLIB$getName$0(); case 20: return new Boolean(var10000.CGLIB$equals$2(var3[0])); case 21: var10000.CGLIB$setName$1((String)var3[0]); return null; case 22: return var10000.CGLIB$clone$5(); case 23: CglibDemo.main((String[])var3[0]); return null; } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); }
这里就是根据方法索引去找方法, 很显然我调用的是getName,那么这个case语句有两个getName:
case 4: return var10000.getName();case 19: return var10000.CGLIB$getName$0();
var10000是代理对象啊(切记), 所以这里不会调用var10000.getName()
因为如果调用的是这个,那么就无限循环调用代理的getName方法了, 好,我们看看代理对象CglibDemo$$EnhancerByCGLIB$$1a76a66
的CGLIB$getName$0
方法:
final String CGLIB$getName$0() { return super.getName(); }
前面介绍了,代理对象是CglibDemo的子类,这里的super就是CglibDemo,所以到这里就调用了CglibDemo的getName方法了:
public String getName() { System.out.println("get name..."); return name; }
到这里, 主体流程讲完了,现在讲下有些细节
一个方法在代理对象的构造
private static Method CGLIB$getName$0$Method; private static MethodProxy CGLIB$getName$0$Proxy; public final String getName() { 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$getName$0$Method, CGLIB$emptyArgs, CGLIB$getName$0$Proxy) : super.getName(); }final String CGLIB$getName$0() { return super.getName();}
每个方法,都有这么些东西:
Method CGLIB$getName$0$Method
反射的原生方法MethodProxy CGLIB$getName$0$Proxy
增强方法,这个方法涉及到FastClass,和方法的索引,方法的索引其实是根据方法的name和参数type的HashCode生成的, 将他的HashCode分配一个int的索引值,比如1,2或者其他数字,比如:
public int getIndex(Signature var1) { String var10000 = var1.toString(); switch(var10000.hashCode()) { case 453440181: if (var10000.equals("CGLIB$getName$0()Ljava/lang/String;")) { return 19; } break; case 1218144844: if (var10000.equals("getName()Ljava/lang/String;")) { return 4; } break;
其中Signature就是根据方法名和参数类型调用toString方法生成的, 方法的hashCode和方法的index是早就对应好了的,因为这些FastClass和代理class都是调用asm生成的,生成的时候,这些就已经对应好了
现在讲解一下FastClass1,也就是如果我在拦截器调用proxy.invoke(obj, args);
会发生啥
invoke的源码:
public Object invoke(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; return fci.f1.invoke(fci.i1, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (IllegalArgumentException e) { if (fastClassInfo.i1 < 0) throw new IllegalArgumentException("Protected method: " + sig1); throw e; } }
跟invokeSuper的唯一区别就是, invoke使用的是fci.f1
也就是FastClass1, 就是CglibDemo$$FastClassByCGLIB$$4320d206
fci.f2
也就是FastClass2,也就是CglibDemo$$EnhancerByCGLIB$$1a76a66$$FastClassByCGLIB$$ea5d0752
那么,FastClass1.invoke发生了啥? ,贴上FastClass1的invoke源码:
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { CglibDemo var10000 = (CglibDemo)var2; int var10001 = var1; try { switch(var10001) { case 0: CglibDemo.main((String[])var3[0]); return null; case 1: return var10000.getName(); case 2: var10000.setName((String)var3[0]); return null; case 3: return new Boolean(var10000.equals(var3[0])); case 4: return var10000.toString(); case 5: return new Integer(var10000.hashCode()); } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); }
好吧,调用的是var10000.getName();
调用的还是代理类的getName,所以又循环调用了,注意注意 CglibDemo var10000 = (CglibDemo)var2;
他不是真的CglibDemo,而是一个代理类, 是CglibDemo$$EnhancerByCGLIB$$1a76a66 extends CglibDemo
好了到这里已经讲解完毕cglib的原理, 以下是问答:
- 源码是使用hsdb从内存直接dump的,也可以System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, “c:\classes”);生成. 这里不介绍这个,以后有时间介绍
- 不可以debug,因为字节码的行号,和反编译的行号对应不上,因为使用的是asm生成的所以行号乱了,不过debug下还是可以看到FastClass的静态字段
- 他的调用方式区别与jdk动态代理,使用的是方法签名的HashCode去case when找到具体方法,所以不是反射,效率会比反射高一点(经过测试,不是特别明显)
- 每个方法都会生成一个MethodProxy, 里面fastClass是一样的,但是方法索引是不同的
最后串一遍流程
proxy.getName() —>intercept.invoke(…)—>methodProxy.invokeSuper()—>fastClass.f2.invoke()—>经过case when找到var10000.CGLIB$getName 0 ( ) − − − − > 然 后 又 到 了 p r o x y , 调 用 C G L I B 0() ----> 然后又到了proxy,调用CGLIB 0()−−−−>然后又到了proxy,调用CGLIBgetName$0----> super.getName() 完毕
转载地址:https://blog.csdn.net/qq_31543867/article/details/108876715 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!