生成署理类文件的办法
jvm增加此启动参数,后边便是署理类class生成的地址
-Dcglib.debugLocation=~/baldhead/java/dynamic-proxy-cglib/src/main/java/com/baldhead/dynamic/proxy/cglib/class
增加这个参数之后,CGLIB就会把生成的署理Class文件存在指定的途径
生成动态署理目标流程
- CGLIB首要生成署理类
- 代码中的 static 静态代码块 会调用
CGLIB$STATICHOOK1();办法,办法效果 3. 新建一个姓名为CGLIB$THREAD_CALLBACKS的ThreadLocal,用来存放所设置的callback4. 使用反射找到署理类中的一切办法,包括(toString、hashCode、equals、clone),姓名为模板CGLIB$METHODNAME$数字编号$Method而且给对应的办法创立署理办法 姓名模板CGLIB$METHODNAME$数字编号$Proxy - 调用结构办法创立署理目标
- 然后CGLIB会调用署理目标的
CGLIB$SET_THREAD_CALLBACKS办法,将传入的callBack存到ThreadLocal(CGLIB$THREAD_CALLBACKS)中去 - 后续在目标履行需求署理的办法的时分,就会从
CGLIB$THREAD_CALLBACKS中拿到所设置的CallBack并调用它的intercept()办法
署理目标的创立
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.baldhead.dynamic.proxy.cglib.Impl.UserService$$EnhancerByCGLIB$$e34eec9a");
Class var1;
CGLIB$test$0$Method = ReflectUtils.findMethods(new String[]{"test", "()V"}, (var1 = Class.forName("com.baldhead.dynamic.proxy.cglib.Impl.UserService")).getDeclaredMethods())[0];
CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()V", "test", "CGLIB$test$0");
}
以上代码通过简化的,主要看下面给出的一行
CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()V", "test", "CGLIB$test$0");
对应的办法如下
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
/**
* 这几个参数都可以找到入参目标
* c1: 被署理类目标的class,也便是原始目标的class
* c2: 署理类目标的 class
* desc: 办法的回来值类型
* name1: 原始署理办法的名称
* name2: 署理办法在署理类中的名称(CGLIB$test$0)
*/
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}
在MethodProxy中有三个很重要的特点
- sig1: 表明test办法
- sig2: 表明 CGLIBtesttest0 办法
- createInfo: 表明原始类和署理类
invoke和invokeSuper办法
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
this.init();
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();
FastClassInfo fci = this.fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
两个办法大差不差的,可是都用到了一个目标 fastClassInfo 这个目标是在 init()办法中结构的
private void init() {
if (this.fastClassInfo == null) {
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
CreateInfo ci = this.createInfo;
FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
fastClassInfo目标中主要是有四个特点
- f1: 原始类对应的一个FastClass 署理目标
- f2: 署理类对应的一个FastClass 署理目标
- i1: test办法在原始类对应的一个FastClass署理目标中的下标
- i2: CGLIBtesttest0办法在署理类对应的一个 FastClass 署理目标中的下标 这儿产生了两个署理目标,你说好巧不巧,正好产生的署理,class有3个,其中有两个承继 FastClass, 另外一个承继原始类而且完成 Factory接口

- 一个结构办法
public int getlndex(Signature var1)public int getlndex(String var1, Classll var2)public int getlndex(ClassI var1)public Object invoke(int var1, Object ar2, Objectll var3)public Object newlnstance(int var1, Objectll var2)public int getMaxlndex0
望文生义,FastClass的效果是提高办法的履行速度,依照正常的完成,当咱们调用MethodProxy目标的invokel或invokeSuper0办法时,首要应该要做到的便是找到对应的Method目标,比方:
-
履行invoke0,要找到test办法对应的Method目标
-
履行invokeSuper0,要找到CGLIBstest$00办法对应的Method目标然后利用反射来履行Method。
那么FastClass的机制便是预先把UserService类或UserService署理类中的一切办法做一个索引,比方:
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 19;
}
break;
case -1659690448:
if (var10000.equals("CGLIB$test$4()V")) {
return 20;
}
break;
case -1457535688:
if (var10000.equals("CGLIB$STATICHOOK1()V")) {
return 12;
}
break;
case -1422510685:
if (var10000.equals("test()V")) {
return 7;
}
break;
case -1411872516:
if (var10000.equals("CGLIB$hashCode$2()I")) {
return 15;
}
break;
// 省略部分代码
}
return -1;
}
一旦调用 getIndex(Signature var1) 办法,就对得到对应办法回来的索引,例如这儿便是test办法回来的对应的索引便是7
再回到init 办法
private void init() {
if (this.fastClassInfo == null) {
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
CreateInfo ci = this.createInfo;
FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
init办法中的两个 helper办法便是去生成原始类和署理类的 FactClass署理类,后边个两个getIndex办法
1. 第一个fci.f1.getIndex(this.sig1)便是去获取原始类对应的FastClass署理类中 test办法的下标i1
2. 第二个 fci.f2.getIndex(this.sig2)便是去获取署理类对应的FastClass署理类中testtest0办法的下标i2
然后会把两个下标都记录在 fastClassInfo 目标中
后边便是咱们看到的invoke和invokeSuper中调用的两个办法
-
invoke
-
fci.f1.invoke(fci.i1, obj, args);履行原始类对应的FastClass 署理类的invoke办法
-
-
invokeSuper
-
fci.f2.invoke(fci.i2, obj, args);履行署理类对应的
FastClass署理类的invoke办法
-
例如: 原始类对应的FastClass 代码
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
UserService var10000 = (UserService)var2;
int var10001 = var1;
try {
switch (var10001) {
case 0:
var10000.test();
return null;
case 1:
return new Boolean(var10000.equals(var3[0]));
case 2:
return var10000.toString();
case 3:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
这个代码比较简单,第一个参数便是履行办法的index,第二个参数便是原始类,第三个便是原始类的参数
假如传入的index 是0 ,那么就会去履行test办法
署理类对应的FastClass署理类的invoke办法也是相似
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
UserService..EnhancerByCGLIB..e34eec9a var10000 = (UserService..EnhancerByCGLIB..e34eec9a)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.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 5:
return var10000.newInstance((Callback[])var3[0]);
case 6:
return var10000.newInstance((Callback)var3[0]);
case 7:
var10000.test();
return null;
case 8:
e34eec9a.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 9:
e34eec9a.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 10:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 11:
return var10000.getCallback(((Number)var3[0]).intValue());
case 12:
return var10000.getCallbacks();
case 13:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 14:
return e34eec9a.CGLIB$findMethodProxy((Signature)var3[0]);
case 15:
e34eec9a.CGLIB$STATICHOOK1();
return null;
case 16:
var10000.CGLIB$test$0();
return null;
case 17:
return new Integer(var10000.CGLIB$hashCode$3());
case 18:
return new Boolean(var10000.CGLIB$equals$1(var3[0]));
case 19:
return var10000.CGLIB$toString$2();
case 20:
return var10000.CGLIB$clone$4();
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
例如传入的index 是16 那么履行的便是 var10000.CGLIB$test$0();
假如传入的index是 7 那么履行的便是var10000.test();
var10000 是传入目标强转为UserService..EnhancerByCGLIB..e34eec9a类的目标,UserService..EnhancerByCGLIB..e34eec9a类其实便是UserService的署理类
invokeSuper结论
所以当咱们履行invokeSuper办法的时分,不能传入原始类(UserService)只能传入署理类目标,否则就无法转换成为署理类类型
所以FastClass 快的地方便是预先把一切的办法信息都生成了对应的index,在真实的去履行的时分不用再去找Method目标,直接传入对应办法的index就可以直接履行对应的办法了
