上一节讲了say方法最终会转发,在demo中
cglib.CglibProxy#intercept这个里面用了
Object result = methodProxy.invokeSuper(o, objects);
这个invokeSuper是什么?如何实现代理类函数的调用 转发到 父类对应函数的调用.
这里就涉及methodProxy以及FastClass机制了。
这两者也是紧密联系的。
先直接讲结论
*** 方法代理的作用就是指明class1.method1方法对应的代理方法是class2.method2 ***
再看代码
先看cglib.CglibProxy#intercept在前面代理类class反编译文件中传递的参数
Object object = methodInterceptor.intercept((Object)this, CGLIB$say$0$Method, CGLIB$emptyArgs, CGLIB$say$0$Proxy);
//CGLIB$say$0$Proxy是什么
CGLIB$say$0$Proxy = MethodProxy.create(class_2, class_, (String)"()V", (String)"say", (String)"CGLIB$say$0");
//其中
Class class_2 = Class.forName("java.lang.Object");
Class class_ = Class.forName("cglib.CglibLearn$serviceImpl$$EnhancerByCGLIB$$4e65f4b");
上面代码中,MethodProxy#create
就是根据参数进行"签名"
A representation of a method signature, containing the method name,
return type, and parameter types.
签名包含方法名称,返回类型,以及参数类型,看源码如下
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;
}
*** 这一段的意义就是说,委托类c1的方法name1,对应的代理方法是实现类c2的方法name2***
再看net.sf.cglib.proxy.MethodProxy#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();
}
}
//init函数干了什么
private void init()
{
/*
单例模式实现
*/
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
/*
生成fastClass f1,f2,结合class文件分析
*/
// System.out.println("net.sf.cglib.proxy.MethodProxy.helper " + ci.c1.getName() + " " + ci.c2.getName() + " " + this.sig1 + " " + this.sig2);
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
/*
获取当前方法在f1,f2中的签名,得到一个index(方法与签名,index是一一对应的关系)
可以根据index映射对应类的对应方法
*/
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
//helper函数干了什么
private static FastClass helper(CreateInfo ci, Class type) {
//根据ci得到该方法的委托类,实现类,分别生成这两个类的fastClass
FastClass.Generator g = new FastClass.Generator();
g.setType(type);
g.setClassLoader(ci.c2.getClassLoader());
g.setNamingPolicy(ci.namingPolicy);
g.setStrategy(ci.strategy);
g.setAttemptLoad(ci.attemptLoad);
return g.create();
}
可以直接参考 http://www.cnblogs.com/cruze/p/3865180.html
这里说的比较简单易懂
主要思想就是在为了避免方法调用时,过度使用反射造成调用慢的问题
给每一个方法一个签名,遇到这个签名时,直接显示调用实现类的实现方法,
可以参考下面的fastClass文件
fastClass的创建时机
从demo中看,fastClass是根据这样的顺序创建的
net.sf.cglib.proxy.MethodProxy#invokeSuper
net.sf.cglib.proxy.MethodProxy#init
net.sf.cglib.proxy.MethodProxy#helper
net.sf.cglib.reflect.FastClass.Generator#create
*** 这里有一种lazy init的思想 ***
也就是说,一开始并没有fastClass,只有MethodProxy
但是当 方法代理 真正被请求的时候
class1的method1方法需要映射到class2的method2方法时,
为了避免过度使用反射,才生成了fastClass方便的完成调用
为了方便理解,
fastClass的创建了几次
即生成了几个fastClass类的class文件
*** 两个,f1和f2(理解成是fast(c1)和fast(c2)) ***
net.sf.cglib.proxy.MethodProxy#init里面调用了两次net.sf.cglib.proxy.MethodProxy#helper
这两个文件的区别是什么
对象 | 意义,实例 |
---|---|
c1 | cglib.CglibLearn$serviceImpl |
f1 | c1的fastClass,更方便调用c1的函数 cglib.CglibLearn$serviceImpl$$FastClassByCGLIB$$4733f381 |
c2 | cglib.CglibLearn$serviceImpl$$EnhancerByCGLIB$$b2e6ff51 即c1的enhance class |
f2 | c2的fastClass,更加方便调用c2的函数, cglib.CglibLearn$serviceImpl$$EnhancerByCGLIB$$b2e6ff51$$FastClassByCGLIB$$8a094902 |
f1,f2都是对原有的c1,c2进行了method->signature->index的映射
fastClass类的内容是如何generate出来的
net.sf.cglib.reflect.FastClass.Generator#generateClass
这里就不细讲了,和上一节Enhancer#generateClass干的事情一样,难度更小,底层还是利用asm生成。
fastClass类的内容是什么
以f1为例 (f2后面筛选一部分出来),即
cglib.CglibLearn$serviceImpl$$FastClassByCGLIB$$4733f381为例子,class反编译的代码如下
package cglib;
import cglib.CglibLearn.serviceImpl;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;
/* compiled from: */
public class CglibLearn$serviceImpl$$FastClassByCGLIB$$4733f381 extends FastClass {
public CglibLearn$serviceImpl$$FastClassByCGLIB$$4733f381(Class cls) {
super(cls);
}
public int getIndex(String str, Class[] clsArr) {
switch (str.hashCode()) {
case -1776922004:
if (str.equals("toString")) {
switch (clsArr.length) {
case 0:
return 5;
default:
break;
}
}
break;
case -1295482945:
if (str.equals("equals")) {
switch (clsArr.length) {
case 1:
if (clsArr[0].getName().equals("java.lang.Object")) {
return 4;
}
break;
default:
break;
}
}
break;
case -1039689911:
if (str.equals("notify")) {
switch (clsArr.length) {
case 0:
return 8;
default:
break;
}
}
break;
case 113643:
if (str.equals("say")) {
switch (clsArr.length) {
case 0:
return 0;
default:
break;
}
}
break;
case 3641717:
if (str.equals("wait")) {
switch (clsArr.length) {
case 0:
return 1;
case 1:
if (clsArr[0].getName().equals("long")) {
return 3;
}
break;
case 2:
if (clsArr[0].getName().equals("long") && clsArr[1].getName().equals("int")) {
return 2;
}
default:
break;
}
}
break;
case 147696667:
if (str.equals("hashCode")) {
switch (clsArr.length) {
case 0:
return 6;
default:
break;
}
}
break;
case 1902066072:
if (str.equals("notifyAll")) {
switch (clsArr.length) {
case 0:
return 9;
default:
break;
}
}
break;
case 1950568386:
if (str.equals("getClass")) {
switch (clsArr.length) {
case 0:
return 7;
default:
break;
}
}
break;
}
return -1;
}
public int getIndex(Signature signature) {
String obj = signature.toString();
switch (obj.hashCode()) {
case -1725733088:
if (obj.equals("getClass()Ljava/lang/Class;")) {
return 7;
}
break;
case -1026001249:
if (obj.equals("wait(JI)V")) {
return 2;
}
break;
case -909388886:
if (obj.equals("say()V")) {
return 0;
}
break;
case 243996900:
if (obj.equals("wait(J)V")) {
return 3;
}
break;
case 946854621:
if (obj.equals("notifyAll()V")) {
return 9;
}
break;
case 1116248544:
if (obj.equals("wait()V")) {
return 1;
}
break;
case 1826985398:
if (obj.equals("equals(Ljava/lang/Object;)Z")) {
return 4;
}
break;
case 1902039948:
if (obj.equals("notify()V")) {
return 8;
}
break;
case 1913648695:
if (obj.equals("toString()Ljava/lang/String;")) {
return 5;
}
break;
case 1984935277:
if (obj.equals("hashCode()I")) {
return 6;
}
break;
}
return -1;
}
public int getIndex(Class[] clsArr) {
switch (clsArr.length) {
case 0:
return 0;
default:
return -1;
}
}
public int getMaxIndex() {
return 9;
}
public Object invoke(int i, Object obj, Object[] objArr) throws InvocationTargetException {
InvocationTargetException invocationTargetException;
serviceImpl cglib_CglibLearn_serviceImpl = (serviceImpl) obj;
switch (i) {
case 0:
try {
cglib_CglibLearn_serviceImpl.say();
return null;
} catch (Throwable th) {
invocationTargetException = new InvocationTargetException(th);
}
case 1:
cglib_CglibLearn_serviceImpl.wait();
return null;
case 2:
cglib_CglibLearn_serviceImpl.wait(((Number) objArr[0]).longValue(), ((Number) objArr[1]).intValue());
return null;
case 3:
cglib_CglibLearn_serviceImpl.wait(((Number) objArr[0]).longValue());
return null;
case 4:
return new Boolean(cglib_CglibLearn_serviceImpl.equals(objArr[0]));
case 5:
return cglib_CglibLearn_serviceImpl.toString();
case 6:
return new Integer(cglib_CglibLearn_serviceImpl.hashCode());
case 7:
return cglib_CglibLearn_serviceImpl.getClass();
case 8:
cglib_CglibLearn_serviceImpl.notify();
return null;
case 9:
cglib_CglibLearn_serviceImpl.notifyAll();
return null;
default:
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
invocationTargetException = new InvocationTargetException(th);
}
public Object newInstance(int i, Object[] objArr) throws InvocationTargetException {
switch (i) {
case 0:
try {
return new serviceImpl();
} catch (Throwable th) {
InvocationTargetException invocationTargetException = new InvocationTargetException(th);
}
default:
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}
}
如何理解上面这段代码,先看父类fastClass的几个函数定义
//根据方法签名的hashCode,获取一个method的标识index
net.sf.cglib.reflect.FastClass#getIndex(net.sf.cglib.core.Signature)
//根据method的标识index,调用实现类的对应方法
net.sf.cglib.reflect.FastClass#invoke(int, java.lang.Object, java.lang.Object[])
*** 为什么说fastClass比反射快 ***
net.sf.cglib.reflect.FastClass#invoke(int, java.lang.Object, java.lang.Object[])函数中,直接创建了实现类对象,通过标识符index去switch case进行对应调用,就像上面的
public Object invoke(int i, Object obj, Object[] objArr) throws InvocationTargetException {
InvocationTargetException invocationTargetException;
serviceImpl cglib_CglibLearn_serviceImpl = (serviceImpl) obj;
switch (i) {
case 0:
try {
cglib_CglibLearn_serviceImpl.say();
return null;
} catch (Throwable th) {
invocationTargetException = new InvocationTargetException(th);
}
//省略
上面invokeSuper返回
fci.f2.invoke(fci.i2, obj, args)
是干了什么
表示用方法代理(否则是f1,这里是f2),将lazy init里面记录好的方法签名对应的标志i2传递过去,让f2进行对应的处理
上面fastclass是f1的,这里只贴出来f2对应部分,f2比较长
类名
cglib.CglibLearn$serviceImpl$$EnhancerByCGLIB$$b2e6ff51$$FastClassByCGLIB$$8a094902
public int getIndex(Signature signature) {
String obj = signature.toString();
switch (obj.hashCode()) {
case 1540695073:
if (obj.equals("CGLIB$say$0()V")) {
return 17;
}
break;
}
}
public Object invoke(int i, Object obj, Object[] objArr) throws InvocationTargetException {
InvocationTargetException invocationTargetException;
b2e6ff51 cglib_CglibLearn_serviceImpl__EnhancerByCGLIB__b2e6ff51 = (b2e6ff51) obj;
switch (i) {
case 17:
cglib_CglibLearn_serviceImpl__EnhancerByCGLIB__b2e6ff51.CGLIB$say$0();
return null;
default:
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}
//cglib_CglibLearn_serviceImpl__EnhancerByCGLIB__b2e6ff51.CGLIB$say$0()函数
final void CGLIB$say$0() {
super.say();//即CglibLearn.serviceImpl.say()方法
}
这里就完成了c1.say到c2.CGLIB$say$0()的转发
可能会有疑问,为什么不是c1.say到c2.say的转发
这是因为在c2里面定义了(上一节也有这段代码,本节最上也有)
CGLIB$say$0$Proxy = MethodProxy.create(class_2, class_, (String)"()V", (String)"say", (String)"CGLIB$say$0");
//其中
Class class_2 = Class.forName("java.lang.Object");
Class class_ = Class.forName("cglib.CglibLearn$serviceImpl$$EnhancerByCGLIB$$4e65f4b");
将Object的say方法 代理 给了 serviceImpl$$EnhancerByCGLIB$$4e65f4b的 CGLIB$say$0方法
即表明,c1的say方法转发到了c2的CGLIB$say$0方法
1.fastclass比反射快的原因
通过方法前面或者标识符index,利用switch case直接利用对象去调用函数
而反射是java.lang.reflect.Method#invoke,稍微复杂点,这个没研究过具体实现
2.MethodProxy#invoke和MethodProxy#invokeSuper什么区别,即[c1,f1]与[c2,f2]的区别
[c1,f1]对应的是 父类的class和fastclass
[c2,f2]对应的是 父类的enhanceClass和 enhanceFastClass
3.MethodProxy#init创建fastclass时,每个method在第一次调用时,都会进行
net.sf.cglib.proxy.MethodProxy#init
net.sf.cglib.proxy.MethodProxy#helper
net.sf.cglib.reflect.FastClass.Generator#create
那么为什么对应的fastclass文件只生成了一次(不是一个method调用一次就生成一次)
并且一次就有整个类的信息,而不是只有这个method相关信息呢
第一点:同一个类的fastClass只生成了一次,
是
net.sf.cglib.reflect.FastClass.Generator#create
net.sf.cglib.core.AbstractClassGenerator#create
里面用了缓存
第二点:一次就有整个类的信息,而不是只有这个method信息
net.sf.cglib.proxy.MethodProxy#create时就传入和class c1,c2
后来创建fastClass时
net.sf.cglib.proxy.MethodProxy#helper
调用了g.setType(type);
在fastClass生成时
net.sf.cglib.reflect.FastClass.Generator#generateClass
用到了这个之前设置好的Class type,也就直到类信息了
invokeSuper的逻辑
4.把invokeSuper改成invoke会怎么样
结论:死循环,堆栈溢出
原因分析:就相当于MethodProxy方法代理中,并没有代理
看c1.say方法,上一节有列举出来
final void say() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
methodInterceptor.intercept(this, CGLIB$say$0$Method, CGLIB$emptyArgs, CGLIB$say$0$Proxy);
} else {
say();
}
}
这里会走到methodInterceptor.intercept,会进过aop
本来调用invokeSuper,在这里如果改成了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;
}
}
会用f1(之前invokeSuper用的f2),f1的代码参照上面列举出来的对应逻辑
//getIndex中say方法前面返回0作为index
public Object invoke(int i, Object obj, Object[] objArr) throws InvocationTargetException {
InvocationTargetException invocationTargetException;
serviceImpl cglib_CglibLearn_serviceImpl = (serviceImpl) obj;
switch (i) {
case 0:
try {
cglib_CglibLearn_serviceImpl.say();
return null;
} catch (Throwable th) {
invocationTargetException = new InvocationTargetException(th);
}
也就是说serviceImpl.say()通过invoke(非invokeSuper)最终还是回到了serviceImpl.say(),变成了递归导致堆栈溢出。
5.methodProxy和fastClass结合使用
methodProxy用于生成方法代理的关系绑定(classA.methodA被classB.methodB代理)
fastClass用于完成方法代理的快速调用,通过签名拿到标识index,避免重复反射
1.methodProxy负责了fastClass的生成,但是methodProxy多次调用生成fastClass,还要让fastClass最终只有一份class文件
也就是调用代理方法时,再创建fastEnhance类,再转发过去
这种lazy的思想感觉超出了自己的职责
2.c1,c2,f1,f2的关系有点绕
3.文档少
4.反编译用http://www.javadecompilers.com/
方式选择CFR (very good and well-supported decompiler for Java 8)
不要选Jadx, fast and with Android support
否则代码会让人误解,比如
//cglib_CglibLearn_serviceImpl__EnhancerByCGLIB__b2e6ff51.CGLIB$say$0()函数在不同反编译方式下
//CFR (very good and well-supported decompiler for Java 8)方式
final void CGLIB$say$0() {
super.say();//即CglibLearn.serviceImpl.say()方法
}
//Jadx, fast and with Android support
final void CGLIB$say$0() {
say();//super没了!!!让我以为invokeSuper函数最终也会产生递归!!!
}
http://www.cnblogs.com/cruze/p/3865180.html
转摘于:https://www.jianshu.com/p/001f866a49d7