CGLIB动态代理原理分析

前提

前一篇文章介绍了CGLIB中常用的API,实际上使用了EnhancerMethodInterceptor之后会生成代理子类,这篇文章就是分析一下CGLIB动态代理的原理。

CGLIB动态代理原理分析

我们经常说CGLIB的动态代理的底层通过被代理类生成代理子类实现的,那么下面我们就分析一下生成的子类到底是什么样的。开启CGLIB的debug模式,输出它生成的类到指定的目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class DebuggingCglibDemo {

private static final String METHOD_NAME = "sayHello";

public static void main(String[] args) throws Exception {
String location = DebuggingCglibDemo.class.getResource("").getPath() + "debugging/";
System.out.println("location -> " + location);
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, location);
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result;
if (METHOD_NAME.equals(method.getName())) {
System.out.println("Before invoking sayHello...");
result = methodProxy.invokeSuper(obj, objects);
System.out.println("After invoking sayHello...");
} else {
result = methodProxy.invokeSuper(obj, objects);
}
return result;
}
});
SampleClass sampleClass = (SampleClass) enhancer.create();
System.out.println(sampleClass.sayHello("throwable"));
}
}

输出结果:

1
2
3
4
5
location -> /D:/Projects/cglib-seed/target/classes/club/throwable/cglib/debugging/
CGLIB debugging enabled, writing to '/D:/Projects/cglib-seed/target/classes/club/throwable/cglib/debugging/'
Before invoking sayHello...
After invoking sayHello...
throwable say hello!

这个时候,看下target下面生成的类如下:

c-d-p-1

一共有五个类:

../net.sf.cglib包下:

MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7.class
Enhancer$EnhancerKey$$KeyFactoryByCGLIB$$7fb24d72.class

这两个类主要很缓存的Key相关,这里不做详细展开。

用户自定义包../club/throwable/cglib包下:

  • SampleClass$$EnhancerByCGLIB$$53c7afed$$FastClassByCGLIB$$da5c8621.class
  • SampleClass$$EnhancerByCGLIB$$53c7afed.class
  • SampleClass$$FastClassByCGLIB$$cf1a549b.class

这三个就是实际使用到的子类,其中有一个是被代理类的直接子类SampleClass$$EnhancerByCGLIB$$53c7afed,其他的两个是FastClass

接着我们先看一下SampleClass$$EnhancerByCGLIB$$53c7afed这个类的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
与Java原生代理类似,仍然以静态变量保存了指向代理方法的引用
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
//每个函数有两个反射方法,一个是通过原生反射获得的,另外一个是通过Cglib构建的。
private static final Method CGLIB$sayHello$0$Method;
private static final MethodProxy CGLIB$sayHello$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;

//这里通过静态代码块初始化上面用到的静态变量,主要使用到反射
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("club.throwable.cglib.SampleClass$$EnhancerByCGLIB$$53c7afed");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "(Ljava/lang/String;)Ljava/lang/String;"}, (var1 = Class.forName("club.throwable.cglib.SampleClass")).getDeclaredMethods())[0];
CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "sayHello", "CGLIB$sayHello$0");
}

//这个方法就是直接调用原来的被代理类(父类)的方法
final String CGLIB$sayHello$0(String var1) {
return super.sayHello(var1);
}
//这个方法就是通过方法代理进行回调,里面用到了Callback实例
public final String sayHello(String var1) {
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$sayHello$0$Method, new Object[]{var1}, CGLIB$sayHello$0$Proxy) : super.sayHello(var1);
}

final boolean CGLIB$equals$1(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$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}

final String CGLIB$toString$2() {
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$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
}

final int CGLIB$hashCode$3() {
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$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}

final Object CGLIB$clone$4() 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$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
}

public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -1816210712:
if (var10000.equals("sayHello(Ljava/lang/String;)Ljava/lang/String;")) {
return CGLIB$sayHello$0$Proxy;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}

return null;
}

public SampleClass$$EnhancerByCGLIB$$53c7afed() {
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) {
SampleClass$$EnhancerByCGLIB$$53c7afed var1 = (SampleClass$$EnhancerByCGLIB$$53c7afed)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);
SampleClass$$EnhancerByCGLIB$$53c7afed var10000 = new SampleClass$$EnhancerByCGLIB$$53c7afed();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}

public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
SampleClass$$EnhancerByCGLIB$$53c7afed var10000 = new SampleClass$$EnhancerByCGLIB$$53c7afed();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}

public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
SampleClass$$EnhancerByCGLIB$$53c7afed var10000 = new SampleClass$$EnhancerByCGLIB$$53c7afed;
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$STATICHOOK1();
}
}

这个类十分长,因为里面有很多的变量,它们都通过了静态代码块使用反射初始化。类的代码比JDK动态代理的子类多,因此生成效率会比较低。相关比较重要的注释已经写在类中,我们最主要关注两点:

  • 第一点:
1
2
private static final Method CGLIB$sayHello$0$Method;
private static final MethodProxy CGLIB$sayHello$0$Proxy;

这两个静态变量都是指向sayHello这个方法,CGLIB$sayHello$0$Method直接指向父类方法,CGLIB$sayHello$0$Proxy是CGLIB生成的方法代理。

  • 第二点:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//这个方法就是直接调用原来的被代理类(父类)的方法
final String CGLIB$sayHello$0(String var1) {
return super.sayHello(var1);
}
//这个方法就是通过方法代理进行回调,里面用到了Callback实例
public final String sayHello(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
//如果找不到Callback会直接调用父类的原方法
return var10000 != null ? (String)var10000.intercept(this, CGLIB$sayHello$0$Method, new Object[]{var1}, CGLIB$sayHello$0$Proxy) : super.sayHello(var1);
}

也就是如果想要启用CGLIB的回调,我们主观上应该是这样操作的:

1
2
SampleClass$$EnhancerByCGLIB$$53c7afed sample = new SampleClass$$EnhancerByCGLIB$$53c7afed();
sample.sayHello("doge");

但是由于这个代理类是动态生成的,只能通过反射调用。

那么,剩下的两个FastClass的作用是什么?我们先看一下MethodProxyinvoke()invokeSuper()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  //初始化FastClass中的index索引
private void init() {
if (this.fastClassInfo == null) {
Object var1 = this.initLock;
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.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;
}
}
}
}

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();
}
}

这里,两个方法各自使用了不同的FastClassInfo实例fci.f2fci.f2。其中,SampleClass$$FastClassByCGLIB$$cf1a549b.class是对应于父类,而SampleClass$$EnhancerByCGLIB$$53c7afed$$FastClassByCGLIB$$da5c8621是对应于CGLIB生成的被代理类的子类。下面展开SampleClass$$EnhancerByCGLIB$$53c7afed$$FastClassByCGLIB$$da5c8621的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
public class SampleClass$$EnhancerByCGLIB$$53c7afed$$FastClassByCGLIB$$da5c8621 extends FastClass {
public SampleClass$$EnhancerByCGLIB$$53c7afed$$FastClassByCGLIB$$da5c8621(Class var1) {
super(var1);
}

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 10;
}
break;
case -1882565338:
if (var10000.equals("CGLIB$equals$1(Ljava/lang/Object;)Z")) {
return 18;
}
break;
case -1816210712:
if (var10000.equals("sayHello(Ljava/lang/String;)Ljava/lang/String;")) {
return 7;
}
break;
case -1457535688:
if (var10000.equals("CGLIB$STATICHOOK1()V")) {
return 15;
}
break;
case -1411842725:
if (var10000.equals("CGLIB$hashCode$3()I")) {
return 19;
}
break;
case -894172689:
if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 5;
}
break;
case -623122092:
if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
return 14;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return 3;
}
break;
case -419626537:
if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
return 13;
}
break;
case 560567118:
if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
return 8;
}
break;
case 811063227:
if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 6;
}
break;
case 973717575:
if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
return 11;
}
break;
case 1221173700:
if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 4;
}
break;
case 1230699260:
if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
return 12;
}
break;
case 1298742135:
if (var10000.equals("CGLIB$sayHello$0(Ljava/lang/String;)Ljava/lang/String;")) {
return 16;
}
break;
case 1306468936:
if (var10000.equals("CGLIB$toString$2()Ljava/lang/String;")) {
return 20;
}
break;
case 1584330438:
if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 9;
}
break;
case 1800494055:
if (var10000.equals("CGLIB$clone$4()Ljava/lang/Object;")) {
return 17;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 0;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return 1;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 2;
}
}

return -1;
}

public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -2012993625:
if (var1.equals("sayHello")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.String")) {
return 7;
}
}
}
break;
case -1983192202:
if (var1.equals("CGLIB$sayHello$0")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.String")) {
return 16;
}
}
}
break;
case -1776922004:
if (var1.equals("toString")) {
switch(var2.length) {
case 0:
return 1;
}
}
break;
case -1295482945:
if (var1.equals("equals")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.Object")) {
return 0;
}
}
}
break;
case -1053468136:
if (var1.equals("getCallbacks")) {
switch(var2.length) {
case 0:
return 11;
}
}
break;
case -124978609:
if (var1.equals("CGLIB$equals$1")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.Object")) {
return 18;
}
}
}
break;
case -60403779:
if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 9;
}
}
}
break;
case -29025555:
if (var1.equals("CGLIB$hashCode$3")) {
switch(var2.length) {
case 0:
return 19;
}
}
break;
case 85179481:
if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 10;
}
}
}
break;
case 94756189:
if (var1.equals("clone")) {
switch(var2.length) {
case 0:
return 3;
}
}
break;
case 147696667:
if (var1.equals("hashCode")) {
switch(var2.length) {
case 0:
return 2;
}
}
break;
case 161998109:
if (var1.equals("CGLIB$STATICHOOK1")) {
switch(var2.length) {
case 0:
return 15;
}
}
break;
case 495524492:
if (var1.equals("setCallbacks")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 13;
}
}
}
break;
case 1154623345:
if (var1.equals("CGLIB$findMethodProxy")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("net.sf.cglib.core.Signature")) {
return 14;
}
}
}
break;
case 1543336189:
if (var1.equals("CGLIB$toString$2")) {
switch(var2.length) {
case 0:
return 20;
}
}
break;
case 1811874389:
if (var1.equals("newInstance")) {
switch(var2.length) {
case 1:
String var10001 = var2[0].getName();
switch(var10001.hashCode()) {
case -845341380:
if (var10001.equals("net.sf.cglib.proxy.Callback")) {
return 5;
}
break;
case 1730110032:
if (var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 4;
}
}
case 2:
default:
break;
case 3:
if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 6;
}
}
}
break;
case 1817099975:
if (var1.equals("setCallback")) {
switch(var2.length) {
case 2:
if (var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) {
return 8;
}
}
}
break;
case 1905679803:
if (var1.equals("getCallback")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("int")) {
return 12;
}
}
}
break;
case 1951977610:
if (var1.equals("CGLIB$clone$4")) {
switch(var2.length) {
case 0:
return 17;
}
}
}

return -1;
}

public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}

public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
53c7afed var10000 = (53c7afed)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((Callback[])var3[0]);
case 5:
return var10000.newInstance((Callback)var3[0]);
case 6:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 7:
return var10000.sayHello((String)var3[0]);
case 8:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 9:
53c7afed.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 10:
53c7afed.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 11:
return var10000.getCallbacks();
case 12:
return var10000.getCallback(((Number)var3[0]).intValue());
case 13:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 14:
return 53c7afed.CGLIB$findMethodProxy((Signature)var3[0]);
case 15:
53c7afed.CGLIB$STATICHOOK1();
return null;
case 16:
return var10000.CGLIB$sayHello$0((String)var3[0]);
case 17:
return var10000.CGLIB$clone$4();
case 18:
return new Boolean(var10000.CGLIB$equals$1(var3[0]));
case 19:
return new Integer(var10000.CGLIB$hashCode$3());
case 20:
return var10000.CGLIB$toString$2();
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}

throw new IllegalArgumentException("Cannot find matching method/constructor");
}

public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
53c7afed var10000 = new 53c7afed;
53c7afed var10001 = var10000;
int var10002 = var1;

try {
switch(var10002) {
case 0:
var10001.<init>();
return var10000;
}
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}

throw new IllegalArgumentException("Cannot find matching method/constructor");
}

public int getMaxIndex() {
return 20;
}
}

这个类更加长,但是其实大部分都是switch-case的代码块,它的功能就是为方法的调用添加基于整型数字的索引,主要目的是为了减少反射调用的时间,将反射调用转化为直接调用。简单来说,invokeSuper的流程就是这样的

  • 通过MethodProxy的init方法,用当前方法的Signature(签名)构建两个FastClass实例(当然,这里会做缓存)和当前方法对应的index,存放在FastClassInfo实例中。
  • 通过FastClassInfo中的FastClass实例和index,在FastClass中找到对应的方法(在switch-case块中基于整数索引index进行查找)直接调用。

直观来看,CGLIB在类生成期间的操作会相对耗时,而且生成的类数目比较多,会占据大量永久代或者元空间的内存。子类一旦生成,后面的方法调用就会变成搜索方法索引和直接调用,这样的操作在特定的条件下效率会比JDK的反射高。这里特定的场景是指CGLIB子类中的switch-case块不大并且当前调用的方法的index在switch-case块的前部而不是中后部(简单来说就是子类中的方法要尽量少从而提高switch-case中的搜寻效率)。详细可以参考这篇性能对比的文章:cglib和jdk动态代理调用性能测

小结

CGLIB提供了许多基于代码生成的高级功能的API,可以在通过上面的例子熟悉它的使用,并且在合适的场景用于实战中。可能最常用到的是基于Enhancer的动态代理,这里总结一下CGLIB和JDK动态代理的区别(老生常谈):

  • JDK动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承);CGLIB能够代理普通类,但是该普通类必须能够被继承(不能用final修饰符)。
  • JDK动态代理使用Java原生的反射API进行操作,在生成类上比较高效;CGLIB使用ASM框架直接对字节码进行修改,使用了FastClass的特性,在某些情况下类的方法执行会比较高效。

(本文完 e-a-20181216 c-1-d)



 评论