我们看看MethodProxy的内部:
public Object invoke(Object obj, Object[] args) throws Throwable { try { this.init(); MethodProxy.FastClassInfo fci = this.fastClassInfo; return fci.f1.invoke(fci.i1, obj, args); } catch (InvocationTargetException var4) { throw var4.getTargetException(); } catch (IllegalArgumentException var5) { if(this.fastClassInfo.i1 < 0) { throw new IllegalArgumentException("Protected method: " + this.sig1); } else { throw var5; } } } public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { this.init(); MethodProxy.FastClassInfo fci = this.fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException var4) { throw var4.getTargetException(); } } ///fastclass private static class FastClassInfo { FastClass f1; FastClass f2; int i1; int i2; private FastClassInfo() { } }
这里有invoke()与invokeSuper()。为啥上面要调用invokeSuper()不调用invoke()呢?
这里就要涉及到CGLB的FastClass机制。 FastClass.机制:为代理类和被代理类各生成一个Class。这个Class会为代理类或被代理类的方法分配一个index(int类型)索引。通过这个索引可以直接定位到要调用的方法,省去了反射。 具体推荐阅读参考1参考2
这里我们只需知道结果:MethodProxy.FastClassInfo 属性的最终值会是
private static class FastClassInfo { FastClass f1;//被代理类UserNoInterface的FastClass FastClass f2;//代理类UserNoInterface?EnhancerByCGLIB?b3361405的FastClass int i1;//被代理类的doSomething()的索引 int i2;//代理类CGLIB$doSomething$0()(内部调用被代理对象的方法)的索引。 private FastClassInfo() { } }
三个文件分别为:
UserNoInterface?EnhancerByCGLIB?b3361405?FastClassByCGLIB?fc90c93c
《代理类的FastClass》UserNoInterface?EnhancerByCGLIB?b3361405
《 cglb生成的代理类》UserNoInterface?FastClassByCGLIB?29e52466
《被代理类的FastClass》
我们在回头看看invoke(),invokeSuper()方法
- invoke() 调用的是fci.f1.invoke(fci.i1, obj, args);也就是调用的是被代理类UserNoInterface的FastClass的invoke方法。
- invokeSuper()调用的是fci.f2.invoke(fci.i2, obj, args);也就是调用的是代理类
UserNoInterface?EnhancerByCGLIB?b3361405的FastClass
的invoke方法.
//=================被代理对象的fastclass的invoke方法 public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { UserNoInterface var10000 = (UserNoInterface)var2; int var10001 = var1; try { switch(var10001) { case 0: var10000.doSomething(); return null; } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); } //=================代理对象的fastclass的invoke方法 public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { b3361405 var10000 = (b3361405)var2; int var10001 = var1; try { switch(var10001) { case 7: var10000.doSomething(); return null; case 15: var10000.CGLIB$doSomething$0(); return null; } } catch (Throwable var4) { throw new InvocationTargetException(var4); } throw new IllegalArgumentException("Cannot find matching method/constructor"); }
我们看到如果调用了MethodProxy.invoke() 会调用被代理对象的fastclass的invoke方法,会调用var10000.doSomething()。而var10000其实就是代理对象,这样就出现了死循环。 这也是网上为啥说的不能在此处使用MethodProxy.invoke()的原因。
看看最终的调用链:
代理对象.doSomething()--->拦截器.intercept()--->MethodProxy.invokeSuper(sub, objects)--->代理类的FastClass类对象的.invoke()--->代理对象的CGLIB$doSomething$0()
方法--->目标对象的方法doSomething()
小结:
- CGLB动态代理可以代理没有实现接口的类
- CGLB动态代理通过Enhancer 实现代理功能
- CGLB动态代理生成一个目标对象的子类。
总结:
- 静态代理从源头解决代理问题
- 动态代理从运行使用时解决代理问题。
- JDK动态代理通过InvocationHandler实现拦截。
- GCLB通过MethodInterceptor实现拦截。
重点:
1.JDK动态是通过反射来实现的。两个要素是Proxy+InvocationHandler
- Proxy 用于创建代理,并且内存中创建的类也继承Proxy
- InvocationHandler增强器,实现对目标方法的增强。
2.CGLB动态代理:两要素Enhancer + MethodInterceptor(CallBack)
- Enhancer创建代理
- MethodInterceptor 增强器, 实现对目标方法增强。
3.JDK代理与CGLB动态代理都在内存中生成新的字节码,最终还是落在Class对象上,
要素是手段,字节码才是目的。JVM并不关心你java代码,他关心的是在内存中可被使用的字节码。
欢迎大家关注我的公众号【源码行动】,最新个人理解及时奉送。