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

https://www.cnblogs.com/cruze/category/593899.html

https://www.cnblogs.com/cruze/p/3865180.html

原文地址:https://www.cnblogs.com/laoxia/p/11127011.html