设计模式之动态代理(二)

前言

上一篇文章我们介绍了JDK动态代理的实现机制/#more),遗留了一些问题,这几天又看了一些资料,把cglib实现动态代理的机制简单了解了一下,今天就分享一下怎么使用cglib实现动态代理和cglib实现的机制。
问题一:JDK动态代理可以嵌套两个代理逻辑吗?
答案是否。之前想的是在main方法中这样写:

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) throws Exception {
Man man = new Man();
TimeInvocationHandler timeHandler = new TimeInvocationHandler(man);
LogInvocationHandler logInvocationHandler = new LogInvocationHandler(timeHandler);

// 动态生成TimeProxy
Human human = (Human) Proxy.newProxyInstance(Human.class, logInvocationHandler);

human.work();
}

这样的话,调用顺序就变成了TimeProxy.work->logInvocationHandler.invoke->timeHandler.work->man.work,但是因为timeHandler并没有实现work方法,所以无法调用下去。
问题二:动态代理的委托类必须实现接口吗?
答案否。cglib的动态代理可以通过继承实现。

cglib的使用

新建一个Woman类

1
2
3
4
5
6
7
public class Woman {

public void work() {
System.out.println("Woman work...");
}

}

然后实现一个叫MethodInterceptor的接口,这个接口类似JDK动态代理的InvocationHandler,都是给了一个实现代理逻辑的标准,cglib实现自己的代理逻辑就要实现这个类,下面给出LogInterceptor的实现。

1
2
3
4
5
6
7
8
9
10
public class LogInterceptor implements MethodInterceptor {

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Log start...");
methodProxy.invokeSuper(o, objects);
System.out.println("Log end...");
return null;
}
}

然后也要像JDK的Proxy.newProxyInstance一下创建代理类,只不过cglib创建代理方式是通过Enhancer类。

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/feidao/Desktop");

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Woman.class);
enhancer.setCallback(new LogInterceptor());
Woman woman = (Woman) enhancer.create();
woman.work();
}

上面的setSuperclass就是设置委托类,setCallback是设置代理逻辑类,就是我们刚才实现MethodInterceptor接口的类,然后调用enhancer.create()就可以生成代理类。
运行结果:

1
2
3
Log start...
Woman work...
Log end...

实现原理

在main方法中加上下面这行代码可以把生成的class写到桌面

1
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/feidao/Desktop");

看下cglib动态生成的class:
生成的class
可以看到cgblib动态生成了三个类,Woman\$$EnhancerByCGLIB$$ad085a.class是生成的代理类,先看下代理类的逻辑:

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
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package proxy;

import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class Woman$$EnhancerByCGLIB$$ad085a extends Woman implements Factory {
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;
private static final Method CGLIB$work$0$Method;
private static final MethodProxy CGLIB$work$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("proxy.Woman$$EnhancerByCGLIB$$ad085a");
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$work$0$Method = ReflectUtils.findMethods(new String[]{"work", "()V"}, (var1 = Class.forName("proxy.Woman")).getDeclaredMethods())[0];
CGLIB$work$0$Proxy = MethodProxy.create(var1, var0, "()V", "work", "CGLIB$work$0");
}

final void CGLIB$work$0() {
super.work();
}

public final void work() {
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$work$0$Method, CGLIB$emptyArgs, CGLIB$work$0$Proxy);
} else {
super.work();
}
}

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 -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 1525100228:
if (var10000.equals("work()V")) {
return CGLIB$work$0$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 Woman$$EnhancerByCGLIB$$ad085a() {
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) {
Woman$$EnhancerByCGLIB$$ad085a var1 = (Woman$$EnhancerByCGLIB$$ad085a)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);
Woman$$EnhancerByCGLIB$$ad085a var10000 = new Woman$$EnhancerByCGLIB$$ad085a();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}

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

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

代理类的方法和静态变量比较多,我们只关心重点。代理类继承了Woman类,我们在main方法中调用了work方法,我们看下work方法做了什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
public final void work() {
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$work$0$Method, CGLIB$emptyArgs, CGLIB$work$0$Proxy);
} else {
super.work();
}
}

首先判断代理逻辑类(也就是我们的LogInterceptor)有没有,有的话调用LogInterceptor的intercept,看下参数:
this就是我们的代理类
CGLIB$work$0$Method是委托类的work方法
CGLIB$emptyArgs就是work方法中的参数
CGLIB$work$0$Proxy是一个包含了委托类和代理类的work方法的类,我们看下MethodProxy的实现。
在LogInterceptor.intercept中调用了MethodProxy.invokeSuper方法

1
2
3
4
5
6
7
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Log start...");
methodProxy.invokeSuper(o, objects);
System.out.println("Log end...");
return null;
}

我们看下methodProxy.invokeSuper代码,传入的参数o就是代理类,objects是参数:

1
2
3
4
5
6
7
8
9
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();
}
}

invokeSuper方法中首先调用了init方法:

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
private void init()
{
/*
* Using a volatile invariant allows us to initialize the FastClass and
* method index pairs atomically.
*
* Double-checked locking is safe with volatile in Java 5. Before 1.5 this
* code could allow fastClassInfo to be instantiated more than once, which
* appears to be benign.
*/
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
CreateInfo ci = createInfo;

FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}

可以看到init方法中生成了FastClassInfo的实例fci,关于FastClassInfo后面详细解释,fci中的f1就是我们的委托类的FastClass(Woman\$$FastClassByCGLIB\$$3c4ac3e2.class),f2就是我们代理类的FastClass(Woman\$$EnhancerByCGLIB$$ad085a$$FastClassByCGLIB$$1fa1fb1b.class),而fci中的i1就是f1中work方法的索引,fci中的i2就是f2中CGLIB$work$0方法的索引。
解释一下FastClass的作用,在JDK动态代理中,我们最后调用委托类的方法的时候是通过反射进行调用的,而在cglib中是通过直接调用完成的,FastClass为每个方法的生成一个索引,调用就通过索引加载实体类完成。直接调用的速度比反射的快一些。
完成init方法后,invokeSuper传入了fci.i2(CGLIB$work$0方法的索引)和代理类的实例,调用了fci.f2.invoke方法,也就是代理类的FastClass的invoke方法,我们来看下该类的invoke方法的实现:

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

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

通过传入的fci.i2的索引就能找到fci.f2(代理类的FastClass)的CGLIB$work$0方法。
实际上,cglib在生成代理类的时候,会为委托类的每个非final方法在代理类中生成两个方法,work方法在代理类中对应的两个方法就是work和CGLIB$work$0。
我们先看下代理类中的CGLIB$work$0方法:

1
2
3
final void CGLIB$work$0() {
super.work();
}

CGLIB$work$0方法中调用了父类的work方法,也就是委托类(Woman)中的work方法。就完成了委托类方法的调用。
上面跟着cglib的源码看可能会有点乱,我们重新再梳理一遍调用流程:
main->Woman\$$EnhancerByCGLIB\$$ad085a.work->logInterceptor.intercept->methodProxy.invokeSuper->Woman\$$EnhancerByCGLIB\$$ad085a\$$FastClassByCGLIB$$1fa1fb1b.invoke->Woman\$$EnhancerByCGLIB\$$ad085a.CGLIB$work$,看起来有点复杂,但其实只要搞清楚代理类和FastClass的关系就比较容易理解,FastClass只是一个辅助类,为了提高性能。

总结

对比一下JDK和cglib动态代理的实现,我们能总结以下几个点:

  1. cglib创建代理类的FastClass的过程比较复杂,因此创建代理类的速度没有JDK快。
  2. cglib使用的是直接调用委托类的方法,jdk使用的是反射调用委托类的方法,至于哪个比较快,网上很多文章说是cglib运行速度会比较快,但我没有做过实验,不予以评论。
  3. jdk完成动态代理,委托类必须实现接口,而cglib不用,但是cglib是通过继承完成动态代理的,所以如果委托类中有final方法,则不能实现动态代理。
  4. cglib通过setCallBacks和setCallbackFilter可以为委托类的单个方法实现单独的代理逻辑,因为比较简单所以没有写出来。

<参考> http://www.cnblogs.com/cruze/p/3865180.html