CGLib原理学习
一、使用示例:
public class UserDaoImpl implements UserDao {
@Override
public void addUser(User user) {
System.out.println("connect to mySQL dataBase.......");
System.out.println("添加用户信息成功...");
}
}
public class LogInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before inteceptor: " + method.getName());
Object obj = methodProxy.invokeSuper(o, objects);
System.out.println("after inteceptor: " + method.getName());
return obj;
}
}
public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "e:\\001\\"); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserDaoImpl.class); enhancer.setCallback(new LogInterceptor()); UserDaoImpl userDao = (UserDaoImpl) enhancer.create(); User user = new User(); userDao.addUser(user); }
二、原理分析:
CGLib生成的代理类继承了委托类,注意如果委托类为final或者方法为final,则该委托类不能被代理;代理类会为委托方法生成两个方法,一个是重写的addUser方法,另一个是CGLIB$addUser$0方法;
当执行代理对象的addUser方法时,会首先判断一下是否存在实现了MethodInterceptor接口的CGLIB$CALLBACK_0;,如果存在,则将调用MethodInterceptor中的intercept方法:
public class UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c extends UserDaoImpl 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;
private static final Method CGLIB$addUser$0$Method;
private static final MethodProxy CGLIB$addUser$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$finalize$1$Method;
private static final MethodProxy CGLIB$finalize$1$Proxy;
private static final Method CGLIB$equals$2$Method;
private static final MethodProxy CGLIB$equals$2$Proxy;
private static final Method CGLIB$toString$3$Method;
private static final MethodProxy CGLIB$toString$3$Proxy;
private static final Method CGLIB$hashCode$4$Method;
private static final MethodProxy CGLIB$hashCode$4$Proxy;
private static final Method CGLIB$clone$5$Method;
private static final MethodProxy CGLIB$clone$5$Proxy;
static void CGLIB$STATICHOOK2() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.ucar.test.service.Impl.UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c");
Class var1;
Method[] 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$finalize$1$Method = var10000[0];
CGLIB$finalize$1$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$1");
CGLIB$equals$2$Method = var10000[1];
CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
CGLIB$toString$3$Method = var10000[2];
CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
CGLIB$hashCode$4$Method = var10000[3];
CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
CGLIB$clone$5$Method = var10000[4];
CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
CGLIB$addUser$0$Method = ReflectUtils.findMethods(new String[]{"addUser", "(Lcom/ucar/test/dto/User;)V"}, (var1 = Class.forName("com.ucar.test.service.Impl.UserDaoImpl")).getDeclaredMethods())[0];
CGLIB$addUser$0$Proxy = MethodProxy.create(var1, var0, "(Lcom/ucar/test/dto/User;)V", "addUser", "CGLIB$addUser$0");
}
final void CGLIB$addUser$0(User var1) {
super.addUser(var1);
}
public final void addUser(User var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$addUser$0$Method, new Object[]{var1}, CGLIB$addUser$0$Proxy);
} else {
super.addUser(var1);
}
}
final void CGLIB$finalize$1() throws Throwable {
super.finalize();
}
protected final void finalize() throws Throwable {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$finalize$1$Method, CGLIB$emptyArgs, CGLIB$finalize$1$Proxy);
} else {
super.finalize();
}
}
final boolean CGLIB$equals$2(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == 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);
}
}
final String CGLIB$toString$3() {
return super.toString();
}
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == 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();
}
final int CGLIB$hashCode$4() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == 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();
}
}
final Object CGLIB$clone$5() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == 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();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -1574182249:
if (var10000.equals("finalize()V")) {
return CGLIB$finalize$1$Proxy;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$5$Proxy;
}
break;
case 1147247458:
if (var10000.equals("addUser(Lcom/ucar/test/dto/User;)V")) {
return CGLIB$addUser$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;
}
public UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c() {
CGLIB$BIND_CALLBACKS(this);
}
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;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c var1 = (UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (CGLIB$STATIC_CALLBACKS == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c var10000 = new UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c var10000 = new UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c var10000 = new UserDaoImpl$$EnhancerByCGLIB$$d79a8f3c;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
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 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 void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
static {
CGLIB$STATICHOOK2();
}
}
在我们的代理类中除了做些增强处理外,还会调用methodProxy.invokeSuper方法来调用委托类的方法;下面看看invokeSuper的代码:
1 public Object invokeSuper(Object obj, Object[] args) throws Throwable { 2 try { 3 init(); 4 FastClassInfo fci = fastClassInfo; 5 return fci.f2.invoke(fci.i2, obj, args); 6 } catch (InvocationTargetException e) { 7 throw e.getTargetException(); 8 } 9 }
在JDK动态代理中方法的调用是通过反射来完成的。但是在CGLIB中,方法的调用并不是通过反射来完成的,而是直接对方法进行调用:FastClass对Class对象进行特别的处理,比如将会用数组保存method的引用,每次调用方法的时候都是通过一个index下标来保持对方法的引用。比如下面的getIndex方法就是通过方法签名来获得方法在存储了Class信息的数组中的下标。
1 private static class FastClassInfo 2 { 3 FastClass f1; 4 FastClass f2; 5 int i1; 6 int i2; 7 }
其中,f1指向委托类对象,f2指向代理类对象,i1和i2分别代表着addUser方法以及CGLIB$addUser$0方法在对象信息数组中的下标。因此对委托对象的调用invoke实际上就是对FastClass的getIndex和invoke的调用,但是在FastClass中的这两个方法都是抽象方法,并没有实现,因此对其调用是在动态生成的FastClass的子类中实现的:
1 abstract public int getIndex(String name, Class[] parameterTypes); 2 abstract public Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException;
1 public class DelegateClass$$FastClassByCGLIB$$4af5b667 extends FastClass {
2
3 /**
4 * 动态子类构造方法
5 */
6 public DelegateClass$$FastClassByCGLIB$$4af5b667(Class delegateClass) {
7 super(delegateClass);
8 }
9
10 /**
11 * 根据方法签名得到方法索引
12 *
13 * @param name 方法名
14 * @param parameterTypes 方法参数类型
15 */
16 public int getIndex(String methodName, Class[] parameterTypes) {
17 switch(methodName.hashCode()) {
18
19 // 委托类方法add索引:0
20 case 96417:
21 if (methodName.equals("add")) {
22 switch(parameterTypes.length) {
23 case 2:
24 if (parameterTypes[0].getName().equals("java.lang.String") &&
25 parameterTypes[1].getName().equals("int")) {
26 return 0;
27 }
28 }
29 }
30 break;
31
32 // 委托类方法addUser索引:1
33 case -838846263:
34 if (methodName.equals("addUser")) {
35 switch(parameterTypes.length) {
36 case 0:
37 return 1;
38 }
39 }
40 break;
41
42 // Object方法equals索引:2
43 case -1295482945:
44 if (methodName.equals("equals")) {
45 switch(parameterTypes.length) {
46 case 1:
47 if (parameterTypes[0].getName().equals("java.lang.Object")) {
48 return 2;
49 }
50 }
51 }
52 break;
53
54 // Object方法toString索引:3
55 case -1776922004:
56 if (methodName.equals("toString")) {
57 switch(parameterTypes.length) {
58 case 0: return 3;
59 }
60 }
61 break;
62
63 // Object方法hashCode索引:4
64 case 147696667:
65 if (methodName.equals("hashCode")) {
66 switch(parameterTypes.length) {
67 case 0:
68 return 4;
69 }
70 }
71 }
72
73 return -1;
74 }
75
76 /**
77 * 根据方法索引调用委托类方法
78 *
79 * @param methodIndex 方法索引
80 * @param delegateInstance 委托类实例
81 * @param parameterValues 方法参数对象
82 */
83 public Object invoke(int methodIndex, Object delegateInstance, Object[] parameterValues) {
84 DelegateClass instance = (DelegateClass) delegateInstance;
85 int index = methodIndex;
86 try {
87 switch(index) {
88 case 0:
89 // 委托类实例直接调用方法语句
90 return new Boolean(instance.add((String)parameterValues[0],
91 ((Number)parameterValues[1]).intValue()));
92 case 1:
93 instance.addUser();
94 return null;
95 case 2:
96 return new Boolean(instance.equals(parameterValues[0]));
97 case 3:
98 return instance.toString();
99 case 4:
100 return new Integer(instance.hashCode());
101 }
102 } catch (Throwable t) {
103 throw new InvocationTargetException(t);
104 }
105
106 throw new IllegalArgumentException("Cannot find matching method/constructor");
107 }
108
109 /**
110 * 根据构造方法描述符(参数类型)找到构造方法索引
111 *
112 * @param parameterTypes 构造方法参数类型
113 */
114 public int getIndex(Class[] parameterTypes) {
115 switch(parameterTypes.length) {
116 // 无参构造方法索引:0
117 case 0:
118 return 0;
119
120 // 有参构造方法索引:1
121 case 1:
122 if (parameterTypes[0].getName().equals("java.lang.String")) {
123 return 1;
124 }
125 default:
126 return -1;
127 }
128 }
129
130 /**
131 * 根据构造方法索引调用委托类构造方法
132 *
133 * @param methodIndex 构造方法索引
134 * @param parameterValues 构造方法参数对象
135 */
136 public Object newInstance(int methodIndex, Object[] parameterValues) {
137 // 创建委托类实例
138 DelegateClass newInstance = new DelegateClass;
139 DelegateClass newObject = newInstance;
140 int index = methodIndex;
141 try {
142 switch(index) {
143 // 调用构造方法(<init>)
144 case 0:
145 newObject.<init>();
146 return newInstance;
147 case 1:
148 newObject.<init>((String)parameterValues[0]);
149 return newInstance;
150 }
151 } catch (Throwable t) {
152 throw new InvocationTargetException(t);
153 }
154
155 throw new IllegalArgumentException("Cannot find matching method/constructor");
156 }
157
158 public int getMaxIndex() {
159 return 4;
160 }
161 }
三、FastClass原理分析:
FastClass使用示例:
1 public class DelegateClass { 2 3 public DelegateClass() { 4 } 5 6 public DelegateClass(String string) { 7 } 8 9 public boolean add(String string, int i) { 10 System.out.println("This is add method: " + string + ", " + i); 11 return true; 12 } 13 14 public void addUser() { 15 System.out.println("This is addUser method"); 16 } 17 }
1 public static void main(String[] args) throws Exception { 2 // 保留生成的FastClass类文件 3 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\Temp\\CGLib\\FastClass"); 4 5 Class delegateClass = DelegateClass.class; 6 7 // Java Reflect 8 9 // 反射构造类 10 Constructor delegateConstructor = delegateClass.getConstructor(String.class); 11 // 创建委托类实例 12 DelegateClass delegateInstance = (DelegateClass) delegateConstructor.newInstance("Tom"); 13 14 // 反射方法类 15 Method addMethod = delegateClass.getMethod("add", String.class, int.class); 16 // 调用方法 17 addMethod.invoke(delegateInstance, "Tom", 30); 18 19 Method addUserMethod = delegateClass.getMethod("addUser"); 20 addUserMethod.invoke(delegateInstance); 21 22 // CGLib FastClass 23 24 // FastClass动态子类实例 25 FastClass fastClass = FastClass.create(DelegateClass.class); 26 27 // 创建委托类实例 28 DelegateClass fastInstance = (DelegateClass) fastClass.newInstance( 29 new Class[] {String.class}, new Object[]{"Jack"}); 30 31 // 调用委托类方法 32 fastClass.invoke("add", new Class[]{ String.class, int.class}, fastInstance, 33 new Object[]{ "Jack", 25}); 34 35 fastClass.invoke("addUser", new Class[]{}, fastInstance, new Object[]{}); 36 }
FastClass原理分析:
FastClass不使用反射类(Constructor或Method)来调用委托类方法,而是动态生成一个新的类(继承FastClass),向类中写入委托类实例直接调用方法的语句,用模板方式解决Java语法不支持问题,同时改善Java反射性能。
动态类为委托类方法调用语句建立索引,使用者根据方法签名(方法名+参数类型)得到索引值,再通过索引值进入相应的方法调用语句,得到调用结果。
1 public abstract class FastClass{ 2 3 // 委托类 4 private Class type; 5 6 // 子类访问构造方法 7 protected FastClass() {} 8 protected FastClass(Class type) { 9 this.type = type; 10 } 11 12 // 创建动态FastClass子类 13 public static FastClass create(Class type) { 14 // Generator:子类生成器,继承AbstractClassGenerator 15 Generator gen = new Generator(); 16 gen.setType(type); 17 gen.setClassLoader(type.getClassLoader()); 18 return gen.create(); 19 } 20 21 /** 22 * 调用委托类方法 23 * 24 * @param name 方法名 25 * @param parameterTypes 方法参数类型 26 * @param obj 委托类实例 27 * @param args 方法参数对象 28 */ 29 public Object invoke(String name, Class[] parameterTypes, Object obj, Object[] args) { 30 return invoke(getIndex(name, parameterTypes), obj, args); 31 } 32 33 /** 34 * 根据方法描述符找到方法索引 35 * 36 * @param name 方法名 37 * @param parameterTypes 方法参数类型 38 */ 39 public abstract int getIndex(String name, Class[] parameterTypes); 40 41 42 /** 43 * 根据方法索引调用委托类方法 44 * 45 * @param index 方法索引 46 * @param obj 委托类实例 47 * @param args 方法参数对象 48 */ 49 public abstract Object invoke(int index, Object obj, Object[] args); 50 51 /** 52 * 调用委托类构造方法 53 * 54 * @param parameterTypes 构造方法参数类型 55 * @param args 构造方法参数对象 56 */ 57 public Object newInstance(Class[] parameterTypes, Object[] args) throws { 58 return newInstance(getIndex(parameterTypes), args); 59 } 60 61 /** 62 * 根据构造方法描述符(参数类型)找到构造方法索引 63 * 64 * @param parameterTypes 构造方法参数类型 65 */ 66 public abstract int getIndex(Class[] parameterTypes); 67 68 /** 69 * 根据构造方法索引调用委托类构造方法 70 * 71 * @param index 构造方法索引 72 * @param args 构造方法参数对象 73 */ 74 public abstract Object newInstance(int index, Object[] args); 75 76 }
三、参考资料:
https://blog.csdn.net/gyshun/article/details/81000997
https://www.runoob.com/w3cnote/cglibcode-generation-library-intro.html
https://www.jianshu.com/p/9a61af393e41?from=timeline&isappinstalled=0