【代理】【六】代理源码解析-Cglib代理-代理文件执行分析
1 前言
上节我们简单看了 Enhancer 的 generateClass 和 firstInstance,两个方法的内容也就是创建代理以及生成代理对象的内容,这节我们结合实际生成的文件了解一下代理的实际执行过程。
2 代理文件分析
我们看一下生成的文件有三个:代理类以及两个FastClass,那我们来看下代理文件的内容。
2.1 代理类
我们首先来看下代理类的内容,我里边去掉一些默认的方法哦比如 equals、toString啥的,只看我们的关键方法哈:
public class UserServiceImpl$$EnhancerByCGLIB$$db94c8d6 extends UserServiceImpl 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; /** * $Method 结尾的就是我们的正常方法比如 say * $Proxy 结尾的是生成方法的代理方法 比如 say的代理方式是 CGLIB$say$0$Proxy * 是通过MethodProxy创建的 用于串联增强逻辑 */ private static final Method CGLIB$say$0$Method; private static final MethodProxy CGLIB$say$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$say2$1$Method; private static final MethodProxy CGLIB$say2$1$Proxy; private static final Method CGLIB$equals$3$Method; private static final MethodProxy CGLIB$equals$3$Proxy; // 静态代码块 static { // 就是下边的这个方法 CGLIB$STATICHOOK1(); } static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; // 记住这里的 var0 是 代理类, var1 是 被代理类 UserServiceImpl Class var0 = Class.forName("net.test.UserServiceImpl$$EnhancerByCGLIB$$db94c8d6"); Class var1; Method[] var10000 = ReflectUtils.findMethods(new String[]{"say", "()V", "say2", "()V"},
(var1 = Class.forName("net.test.UserServiceImpl")).getDeclaredMethods()); CGLIB$say$0$Method = var10000[0]; CGLIB$say$0$Proxy = MethodProxy.create(var1, var0, "()V", "say", "CGLIB$say$0"); CGLIB$say2$1$Method = var10000[1]; CGLIB$say2$1$Proxy = MethodProxy.create(var1, var0, "()V", "say2", "CGLIB$say2$1"); 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$equals$3$Method = var10000[1]; CGLIB$equals$3$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3"); } // 空参构造 public UserServiceImpl$$EnhancerByCGLIB$$db94c8d6() { // 调用下边这个方法 CGLIB$BIND_CALLBACKS(this); } // var0 就是代理对象本身 private static final void CGLIB$BIND_CALLBACKS(Object var0) { UserServiceImpl$$EnhancerByCGLIB$$db94c8d6 var1 = (UserServiceImpl$$EnhancerByCGLIB$$db94c8d6)var0; // CGLIB$BOUND 第一次进来为 false if (!var1.CGLIB$BOUND) { // 再设置为 true var1.CGLIB$BOUND = true; /** * 从本地线程中获取增强逻辑,没有的话就用类信息里的 * 也就是我们上节 firstInstance 方法会塞进来我们的增加逻辑的哪个类也就是 MyMethodInterceptor */ Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if (var10000 == null) { // 本地线程中没有的就用类信息里的 var10000 = CGLIB$STATIC_CALLBACKS; if (var10000 == null) { return; } } // 设置进 CGLIB$CALLBACK_0 var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0]; } } final void CGLIB$say$0() { super.say(); } public final void say() { 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$say$0$Method, CGLIB$emptyArgs, CGLIB$say$0$Proxy); } else { super.say(); } } }
可以看到代理对象静态代码块,就会创建每个方法的代理方法出来,并设置上增强逻辑的回调,那么我么你先看下方法代理的创建:
/** * MethodProxy * @param c1 被代理类 UserServiceImpl * @param c2 代理类 * @param desc 方法描述 比如 ()V (Ljava/lang/Object;)Z * @param name1 正常的方法名 比如 say 这个会走增强逻辑 * @param name2 代理的方法名 比如 CGLIB$say$0 但是你看它生成的类 这个方法反而直接简单是调用父类的 也就是说不会走增强逻辑 * @return */ public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) { MethodProxy proxy = new MethodProxy(); proxy.sig1 = new Signature(name1, desc); proxy.sig2 = new Signature(name2, desc); proxy.createInfo = new CreateInfo(c1, c2); return proxy; }
private static class CreateInfo { Class c1; Class c2; NamingPolicy namingPolicy; GeneratorStrategy strategy; boolean attemptLoad; public CreateInfo(Class c1, Class c2) { // 被代理类 UserServiceImpl this.c1 = c1; // 代理类 this.c2 = c2; AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent(); if (fromEnhancer != null) { namingPolicy = fromEnhancer.getNamingPolicy(); strategy = fromEnhancer.getStrategy(); attemptLoad = fromEnhancer.getAttemptLoad(); } } }
一定分析清楚我们的c1、c2 表示的啥哈。
2.2 FastClass
两个 FastClass我们只看其中一个哈,因为生成的方法都是一样的,内容上格式都差不多:
package net.test; import java.lang.reflect.InvocationTargetException; import net.sf.cglib.core.Signature; import net.sf.cglib.reflect.FastClass; public class UserServiceImpl$$FastClassByCGLIB$$65337df extends FastClass { public UserServiceImpl$$FastClassByCGLIB$$65337df(Class var1) { super(var1); } public int getIndex(Signature var1) { String var10000 = var1.toString(); switch(var10000.hashCode()) {case -909388886: if (var10000.equals("say()V")) { return 0; } break;case 1874011246: if (var10000.equals("say2()V")) { return 1; } break;return -1; } public int getIndex(String var1, Class[] var2) { switch(var1.hashCode()) {case 113643: if (var1.equals("say")) { switch(var2.length) { case 0: return 0; } } break; case 3522983: if (var1.equals("say2")) { switch(var2.length) { case 0: return 1; } } break; return -1; } public int getIndex(Class[] var1) { switch(var1.length) { case 0: return 0; default: return -1; } } public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { UserServiceImpl var10000 = (UserServiceImpl)var2; int var10001 = var1; try { switch(var10001) { case 0: var10000.say(); return null; case 1: var10000.say2(); return null; } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); }public int getMaxIndex() { return 10; } }
3 方法的实际执行过程
看过了cglib代理产生的东西以后,我有一个困惑的就是 FastClass 是什么时候发挥作用的呢,还没看到是不是,那么我们从一个实际的方法调用我们看下执行的过程:
public static void main(String[] args) { // 设置代理文件输出位置 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./code"); // 创建 cglib 代理类的核心对象 Enhancer enhancer = new Enhancer(); // 设置要创建代理的类 enhancer.setSuperclass(UserServiceImpl.class); // 跟 JDK 代理一样,增强的逻辑 enhancer.setCallback(new MyMethodInterceptor()); // 创建代理,并调用 UserServiceImpl userService = (UserServiceImpl) enhancer.create(); userService.say(); }
也就是调用我们的 say 方法后执行开始:
public final void say() { // 我们的增强逻辑 MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; /** * Enhancer 里的 firstInstance的方法在创建代理对象的时候已经初始化上了 * 所以这里不空 */ if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } // 不空执行代理我们的增强逻辑 也就是我们的 MyMethodInterceptor if (var10000 != null) { var10000.intercept(this, CGLIB$say$0$Method, CGLIB$emptyArgs, CGLIB$say$0$Proxy); } else { super.say(); } }
然后我们看下我们的增强逻辑:
/** * * @param o this 也就是我们的代理对象 * @param method intercepted Method say方法 * @param objects 方法参数 * @param methodProxy 代理类的代理方法 也就是MethodProxy类型的 CGLIB$say$0$Proxy * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("我是执行前"); Object result = methodProxy.invokeSuper(o, objects); System.out.println("我是执行后"); return result; }
继续我们看下 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(); } } private void init() { if (fastClassInfo == null) { synchronized (initLock) { if (fastClassInfo == null) { CreateInfo ci = createInfo; FastClassInfo fci = new FastClassInfo(); // f1 被代理类 fci.f1 = helper(ci, ci.c1); // f2 代理类 fci.f2 = helper(ci, ci.c2); // 被代理类的FastClass say 方法的索引 fci.i1 = fci.f1.getIndex(sig1); // 代理类的FastClass CGLIB$say$0 方法的索引 fci.i2 = fci.f2.getIndex(sig2); fastClassInfo = fci; } } } }
我们看到最后调的是 fci.f2.invoke 也就是:
是不是这样就完事?不知道你有没有晕掉,我这里补了个图,梳理一下:
3.1 问题一:我这里不调用invokeSuper 调用 invoke 会发生什么呢?
首先我们要知道 invoke里内容是什么我们来看下:
可以看到 invokeSuper是调用的f2.invoke,invoke是调用的f1.invoke 也就是调用say 方法是不是? 那么我们当前的对象是代理对象,代理对象的say方法又是什么呢?
看就是还是会走增强逻辑也就是说进入一个死循环了,是不是就会栈溢出了。
来看图:
3.2 问题二:那我不调用MethodProxy的了,我直接调用Method呢?
我直接说答案了奥,就不贴图了哈,其实还是会死循环,因为Method就还是 say方法,一定注意的是我们当前的对象就是 代理对象,代理对象的 say方法里是走增强逻辑的,所以还是会死循环。
4 小结
这节我们看了下代理实际的执行过程,也看到了 FastClass的调用时机就是 执行我们的代理方法的invoke时,init方法里会初始化FastClass,然后获取到当前方法的索引,继而进行调用。有理解不对的地方欢迎指正哈。