设计模式之结构型设计模式-代理模式

1. 模式简介

为其他对象提供一种代理,以控制对这个对象的访问;代理对象就类似生活中的中介;属于结构型设计模式

2. 示例代码

2.1. 静态代理

显式声明被代理对象,仅可以代理某些对象

2.1.1. 代码实现

  • 具体实现
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
/**
* <p>
* 售票接口
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 22:12
*/
public interface Ticket {
/**
* 卖票
*/
void sell();
}

/**
* <p>
* 演唱会门票
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 22:16
*/
public class MusicTicket implements Ticket {
/**
* 卖票
*/
@Override
public void sell() {
System.out.println("卖演唱会门票");
}
}

/**
* <p>
* 静态代理类,演唱会售票员(只卖演唱会门票)
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 22:24
*/
public class MusicConductor implements Ticket {
private MusicTicket ticket;

/**
* 只代理 演唱会门票
* @param ticket 演唱会门票
*/
public MusicConductor(MusicTicket ticket) {
this.ticket = ticket;
}

/**
* 卖票
*/
@Override
public void sell() {
before();
this.ticket.sell();
after();
}

private void before() {
System.out.println("静态代理 - 方法前增强");
}

private void after() {
System.out.println("静态代理 - 方法后增强");
}
}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* <p>
* 代理模式 - 静态代理,测试类
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 22:29
*/
public class PatternTest {
public static void main(String[] args) {
MusicConductor conductor = new MusicConductor(new MusicTicket());
conductor.sell();
}
}
  • 测试结果
1
2
3
静态代理 - 方法前增强
卖演唱会门票
静态代理 - 方法后增强

2.1.2. UML 图例

代理模式-静态代理

2.2. 动态代理

动态配置和替换被代理对象,通俗的说就是可以代理任意一类对象,甚至是任意对象

2.2.1. JDK 动态代理

注意:JDK代理时被代理类必须实现接口

2.2.1.1. 代码实现
  • 具体实现
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
/**
* <p>
* 售票接口
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 22:12
*/
public interface Ticket {
/**
* 卖票
*/
void sell();
}

/**
* <p>
* 演唱会门票
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 22:16
*/
public class MusicTicket implements Ticket {
/**
* 卖票
*/
@Override
public void sell() {
System.out.println("卖演唱会门票");
}
}

/**
* <p>
* 体育比赛门票
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 23:07
*/
public class SportTicket implements Ticket {
/**
* 卖票
*/
@Override
public void sell() {
System.out.println("体育比赛门票");
}
}

/**
* <p>
* JDK动态代理类,售票员(不论什么票都卖)
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 22:35
*/
public class Conductor implements InvocationHandler {
/**
* 被代理对象
*/
private Object target;

/**
* 可以代理任意门票,所以为 {@link Object}
*
* @param target 被代理对象,但是必须有统一的接口
* @return 被代理对象
*/
public Object getInstance(Object target) {
this.target = target;
Class<?> clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}

/**
* 反射调用的方法
*
* @param proxy 代理对象
* @param method 被代理对象需要执行的方法
* @param args 被代理对象需要执行的方法 的参数
* @return 被代理对象需要执行的方法 的返回值
* @throws Throwable 抛出异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
}

private void before() {
System.out.println("动态代理 - JDK动态代理 - 方法前增强");
}

private void after() {
System.out.println("动态代理 - JDK动态代理 - 方法后增强");
}
}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* <p>
* 代理模式 - 动态代理 - JDK动态代理,测试类
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 23:04
*/
public class PatternTest {
public static void main(String[] args) {
// 代理演唱会门票
Ticket musicTicket = (Ticket) new Conductor().getInstance(new MusicTicket());
musicTicket.sell();

// 代理运动会门票
Ticket sportTicket = (Ticket) new Conductor().getInstance(new SportTicket());
sportTicket.sell();
}
}
  • 测试结果
1
2
3
4
5
6
动态代理 - JDK动态代理 - 方法前增强
卖演唱会门票
动态代理 - JDK动态代理 - 方法后增强
动态代理 - JDK动态代理 - 方法前增强
体育比赛门票
动态代理 - JDK动态代理 - 方法后增强
2.2.1.2. UML 图例
代理模式-动态代理-JDK动态代理

2.2.2. CGLIB 动态代理

注意:CGLIB不能代理 final 修饰的类/方法

2.2.2.1. 代码实现
  • 具体实现
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
/**
* <p>
* 火车票
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 23:18
*/
public class TrainTicket {
public void sell() {
System.out.println("火车票");
}
}

/**
* <p>
* CGLIB动态代理类,售票员(不论什么票都卖)
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 22:35
*/
public class Conductor implements MethodInterceptor {

public Object getInstance(Class<?> clazz) {
// Enhancer 相当于 JDK 动态代理的 Proxy 类
Enhancer enhancer = new Enhancer();
// 设置动态生成的对象的父类为传进来的 被代理类
enhancer.setSuperclass(clazz);
// MethodInterceptor 继承 Callback 接口
enhancer.setCallback(this);
return enhancer.create();
}

/**
* 代理对象执行的所有方法都会走这个方法
*
* @param o 被代理的对象
* @param method 被代理对象需要执行的方法
* @param objects 被代理对象需要执行的方法 参数
* @param methodProxy 触发父类的方法对象
* @return 被代理对象需要执行的方法 返回值
* @throws Throwable 抛出的异常信息
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
// 调用生成代理对象的父类方法
Object result = methodProxy.invokeSuper(o, objects);
after();
return result;
}

private void before() {
System.out.println("动态代理 - CGLIB动态代理 - 方法前增强");
}

private void after() {
System.out.println("动态代理 - CGLIB动态代理 - 方法后增强");
}

}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* <p>
* 代理模式 - 动态代理 - CGLIB动态代理,测试类
* </p>
*
* @author yangkai.shen
* @date Created in 2019-08-20 23:16
*/
public class PatternTest {
public static void main(String[] args) {
// 代理火车票
TrainTicket trainTicket = (TrainTicket) new Conductor().getInstance(TrainTicket.class);
trainTicket.sell();

// 代理演唱会门票
MusicTicket musicTicket = (MusicTicket) new Conductor().getInstance(MusicTicket.class);
musicTicket.sell();
}
}
  • 测试结果
1
2
3
4
5
6
动态代理 - CGLIB动态代理 - 方法前增强
火车票
动态代理 - CGLIB动态代理 - 方法后增强
动态代理 - CGLIB动态代理 - 方法前增强
卖演唱会门票
动态代理 - CGLIB动态代理 - 方法后增强
2.2.2.2. UML 图例
代理模式-动态代理-CGLIB动态代理

3. 应用

1
// Spring AOP

4. 场景

  • 保护目标对象
  • 增强目标对象

5. 优缺点

优点: 代理模式能将代理对象与真实被调用的目标对象分离;一定程度上降低了系统的耦合程度,易于扩展;代理可以起到保护目标对象的作用; 增强目标对象的职责

缺点: 代理模式会造成系统设计中类的数目增加;在客户端和目标对象之间增加了一个代理对象,会造成请求处 理速度变慢;增加了系统的复杂度

6. 拓展

6.1. JDK 动态代理的原理分析

  • 原理简介
1
2
3
4
5
6
7
8
9
// 1. 拿到被代理的对象的引用,反射获取所有接口

// 2. JDK 的 Proxy 类重新生成一个新的类,实现了被代理对象的所有接口

// 3. Proxy 根据字节码动态生成 Java 代码,把增强的逻辑加入到新生成的代码中

// 4. 编译生成的 Java 代码对应的 class 文件

// 5. 通过 ClassLoader 加载并重新运行新的 class 文件(注意这个 class 文件就是一个全新的类)
  • 源码剖析

首先我们将断点打在 这个位置 如下图所示,可以发现,此时这个 musicTicket 对象的引用有点奇怪,居然是 $Proxy0@554,证明该对象是通过代理生成的新的代理类创建的,而不是由原生的 MusicTicket 类创建的。

为什么嘞?我们来瞄一波源码。

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
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
// 1. musicTicket 是通过我们定义的 getInstance 方法返回的,在 getInstance 方法里,我们通过调用 Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this)

// 2. 我们看看 java.lang.reflect.Proxy#newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
// java.lang.reflect.Proxy#newProxyInstance 主要工作就是①生成代理类②根据代理类获取构造方法③通过构造方法生成代理对象
// ①生成代理类 -> Class<?> cl = getProxyClass0(loader, intfs);
// ②根据代理类获取构造方法 -> final Constructor<?> cons = cl.getConstructor(constructorParams);
// ③通过构造方法生成代理对象 -> return cons.newInstance(new Object[]{h});

// 3. 这里的重点在于生成代理类,所以我们看看 getProxyClass0 这个方法 -> java.lang.reflect.Proxy#getProxyClass0(ClassLoader loader,Class<?>... interfaces)

/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
* 生成代理类,调用该方法前,必须先执行checkProxyAccess方法校验是否可以生成代理类。
*/
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {
// 这里需要注意:接口的数量有最大限制,不可以超过 65535
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}

// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
// 如果缓存中存在代理类,则直接返回,如果不存在,则会调用ProxyClassFactory类生成代理类
return proxyClassCache.get(loader, interfaces);
}

// 4. 我们首次调用的时候,缓存里肯定是不存在的,所以我们先看看这个 proxyClassCache 到底是何方神圣?
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

// 4.1. 这里的 WeakCache 是JDK自己通过 ConcurrentMap 实现的一个缓存
// 4.2. 键:KeyFactory 就是 ClassLoader 类加载器
// 4.3. 值:ProxyClassFactory 就是代理类的工厂类对象

//5. 我们查看下 java.lang.reflect.WeakCache#get(K key, P parameter) 这个方法里到底是怎么处理的
/**
* @param key 类加载器
* @param parameter 接口数组
*/
public V get(K key, P parameter) {
// 校验接口数组,必须存在接口,否则直接抛出 NPE
Objects.requireNonNull(parameter);

// 清除已经被GC回收的对象引用
expungeStaleEntries();

// 将 ClassLoader 转化为 CacheKey,此时cacheKey为一级缓存的key
Object cacheKey = WeakCache.CacheKey.valueOf(key, refQueue);

// lazily install the 2nd level valuesMap for the particular cacheKey
// 根据一级缓存的key获取二级缓存
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
// 二级缓存不存在,创建一个空的二级缓存
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}

// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
// 根据 ClassLoader 和 接口数组,创建二级缓存的key
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 通过二级缓存的key获取值
Supplier<V> supplier = valuesMap.get(subKey);
WeakCache.Factory factory = null;

// 死循环重试,直到返回对象为止
while (true) {
// 程序的出口分支
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
// 根据下方的方法可以看出 supplier 可能是 WeakCache.Factory 也可能是 CacheValue
// 具体验证的细节,在 supplier 的实现类里去判断是什么类型,然后将值返回
V value = supplier.get();
// 如果拿到对象,则退出循环,拿不到对象,继续走循环重试
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)

// lazily construct a Factory
// 如果二级缓存的key取不到值,并且Factory不存在,则去创建Factory对象,这一条件分支,若执行,仅会执行一次
// 在下方代码可见,创建的Factory对象会去充当二级缓存的值
if (factory == null) {
factory = new WeakCache.Factory(key, parameter, subKey, valuesMap);
}

if (supplier == null) {
// 如果二级缓存的key取不到值, 就将factory作为二级缓存对应的值放入
// 防止被其他线程修改,所以使用 putIfAbsent 方法是如果存在 subKey,就取出来直接用,如果不存在,则将 factory 放入
supplier = valuesMap.putIfAbsent(subKey, factory);
// 存放失败的情况,强制将 supplier = factory,此时factory成功加入二级缓存
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
// 如果被其他线程修改,就尝试将factory替换旧值
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
// 替换成功
supplier = factory;
} else {
// retry with current supplier
// 替换失败,则继续使用旧值
supplier = valuesMap.get(subKey);
}
}
}
}

// 6. 根据如上代码,这里关键就2点:①二级缓存key的创建②二级缓存只的获取
// ①二级缓存key的创建 -> Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// ②二级缓存值的获取 -> V value = supplier.get();

// 7. 首先我们来看看二级缓存key的创建,这里通过 subKeyFactory.apply() 获取,那么这个 subKeyFactory 是什么呢?我们可以跟踪源码发现,这是通过 WeakCache 的构造方法传入的参数,也就是说,是在 Proxy 类里创建 proxyClassCache 的是传入的,所以这个 subKeyFactory 就是 java.lang.reflect.Proxy.KeyFactory 类的对象

/**
* A function that maps an array of interfaces to an optimal key where
* Class objects representing interfaces are weakly referenced.
* 将接口数组映射为一个最优的键去代表接口的实现类的弱引用的方法
*/
private static final class KeyFactory
implements BiFunction<ClassLoader, Class<?>[], Object>
{
@Override
public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
switch (interfaces.length) {
// 这里的 Proxy.key1....这些就是根据哈希值计算key
case 1: return new Proxy.Key1(interfaces[0]); // the most frequent
case 2: return new Proxy.Key2(interfaces[0], interfaces[1]);
case 0: return key0;
default: return new Proxy.KeyX(interfaces);
}
}
}

// 8. 然后我们到了关键的地方,敲黑板,划重点了!!!我们来看下二级缓存值的获取,在WeakCache中是通过 supplier.get() 获取的,那么关键就是这个 supplier 了。
// 还记得上面说过的,V value = supplier.get() 取到的可能是 WeakCache.Factory 也可能是 CacheValue
// 那我们看看 WeakCache.Factory

/**
* A factory {@link Supplier} that implements the lazy synchronized
* construction of the value and installment of it into the cache.
* 将值设置进缓存的工厂类,线程安全
*/
private final class Factory implements Supplier<V> {

private final K key;
private final P parameter;
private final Object subKey;
private final ConcurrentMap<Object, Supplier<V>> valuesMap;

Factory(K key, P parameter, Object subKey, ConcurrentMap<Object, Supplier<V>> valuesMap) {
this.key = key;
this.parameter = parameter;
this.subKey = subKey;
this.valuesMap = valuesMap;
}

@Override
public synchronized V get() { // serialize access
// re-check
// 双重检查,缓存中是否已存在二级缓存key
Supplier<V> supplier = valuesMap.get(subKey);
// 之所以之前不去校验,是因为这里会去判断,是否是 WeakCache.Factory 对象还是 CacheValue
// 有可能被替换成了 CacheValue 或者被移除了
// 总之如果是不是 Factory 对象本身,就返回 null,继续之前的死循环
if (supplier != this) {
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop

return null;
}
// else still us (supplier == this)

// create new value
V value = null;
try {
// 这里调用 valueFactory.apply(key, parameter) 获取值
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
assert value != null;

// wrap value with CacheValue (WeakReference)
// 将返回的对象,包装成 CacheValue(弱引用)
WeakCache.CacheValue<V> cacheValue = new WeakCache.CacheValue<>(value);

// put into reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);

// try replacing us with CacheValue (this should always succeed)
if (!valuesMap.replace(subKey, this, cacheValue)) {
throw new AssertionError("Should not reach here");
}

// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
}

// 观察 java.lang.reflect.WeakCache.Factory 这个类的 get 方法可以发现,这里解决前面没有去判断返回值类型的坑
// 如果不是 Factory 对象本身,就返回 null,继续之前的死循环
// 如果是 Factory 对象,就通过 value = Objects.requireNonNull(valueFactory.apply(key, parameter)) 获取值
// 所以这个 valueFactory 就是关键的地方,有了上面 subKeyFactory 的经验,我们可以很快知道这个 valueFactory 也是在构造 WeakCache 传进来的,也就是说,是在 Proxy 类里创建 proxyClassCache 的是传入的,所以这个 valueFactory 就是 java.lang.reflect.Proxy.ProxyClassFactory 类的对象

// 9. 接下来就需要来拜读下这个 java.lang.reflect.Proxy.ProxyClassFactory 这个类的源码了

/**
* A factory function that generates, defines and returns the proxy class given
* the ClassLoader and array of interfaces.
* 根据 ClassLoader 和 接口数组生成、定义和返回给定的代理类的工厂函数
*/
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
// 定义了所有代理类的名称前缀为「$Proxy」
private static final String proxyClassNamePrefix = "$Proxy";

// next number to use for generation of unique proxy class names
// 为代理类对象生成编号,从0递增,如 $Proxy0、$Proxy1 等
// 使用 AtomicLong 原子类保证线程安全
private static final AtomicLong nextUniqueNumber = new AtomicLong();

@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
* 检查指定的ClassLoader加载接口得到的Class对象是否和接口数组遍历得到的Class对象相同
*/
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
// 不相同则抛出异常
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
* 检查当前 Class 对象不是一个接口
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
* 检查当前接口是否重复
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}

// 声明代理类所在的包
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
* 记录所有非public的代理接口的包路径,验证是否代理接口再同一个包下。
* 公共接口无需处理,只验证非public接口
*/
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
// 字符串截取包名
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}

// 如果都是 public 修饰的接口,那么就将代理类的包名设置为 ReflectUtil.PROXY_PACKAGE -> com.sun.proxy
// 注意:万一出现 java.io.FileNotFoundException: com\sun\proxy\$Proxy0.class 这个异常,可以通过在项目路径手动创建 com.sun.proxy 包解决
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}

/*
* Choose a name for the proxy class to generate.
* 生成代理类序号
*/
long num = nextUniqueNumber.getAndIncrement();

// 代理类名称,类似:com.sun.proxy.$Proxy0.class
String proxyName = proxyPkg + proxyClassNamePrefix + num;

/*
* Generate the specified proxy class.
* 生成具体的类字节码,重点!!!
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}

// 好了,重头戏开始了,生成代理类文件的具体代码就要出现了
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);

// 10. 我们来看看 sun.misc.ProxyGenerator#generateProxyClass(final String var0, Class<?>[] var1, int var2)这个方法到底做了什么神奇的事情
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
// 这里才真正调用了生成类字节码的方法
final byte[] var4 = var3.generateClassFile();
// 如果需要将生成的字节码保存下来的话,就需要在这里设置 saveGeneratedFiles -> true
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}

Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}

return var4;
}

// 11. 得,生成字节码的代码还藏了一层!不过也算是终于见到庐山真面目了,同时我们还发现了,我们也可以通过设置参数saveGeneratedFiles将生成的代理类保存下来。
// 12. 最后看看生成字节码的方法吧,sun.misc.ProxyGenerator#generateClassFile
private byte[] generateClassFile() {
// 添加 hashCode 代理方法
this.addProxyMethod(hashCodeMethod, Object.class);
// 添加 equals 代理方法
this.addProxyMethod(equalsMethod, Object.class);
// 添加 toString 代理方法
this.addProxyMethod(toStringMethod, Object.class);
Class[] var1 = this.interfaces;
int var2 = var1.length;

int var3;
Class var4;
// 遍历所有接口中的所有方法,并将所有方法添加代理方法
for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
Method[] var5 = var4.getMethods();
int var6 = var5.length;

for(int var7 = 0; var7 < var6; ++var7) {
Method var8 = var5[var7];
this.addProxyMethod(var8, var4);
}
}

Iterator var11 = this.proxyMethods.values().iterator();

List var12;
// 校验方法返回值
while(var11.hasNext()) {
var12 = (List)var11.next();
checkReturnTypes(var12);
}

Iterator var15;
try {
// 添加代理类的构造方法
this.methods.add(this.generateConstructor());
var11 = this.proxyMethods.values().iterator();

while(var11.hasNext()) {
var12 = (List)var11.next();
var15 = var12.iterator();

while(var15.hasNext()) {
ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();
this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));
// 生成代理类的代理方法
this.methods.add(var16.generateMethod());
}
}

// 生成静态代码块等初始化信息
this.methods.add(this.generateStaticInitializer());
} catch (IOException var10) {
throw new InternalError("unexpected I/O Exception", var10);
}

// 代理类的方法个数不可以超过 65535 个
if (this.methods.size() > 65535) {
throw new IllegalArgumentException("method limit exceeded");
}
// 代理类的字段个数不可以超过 65535 个
else if (this.fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
}
// 都满足要求,开始写出字节码文件
else {
// 将类名、java/lang/reflect/Proxy、以及接口数组等信息保存进 cp 中,cp是一个常量池
this.cp.getClass(dotToSlash(this.className));
this.cp.getClass("java/lang/reflect/Proxy");
var1 = this.interfaces;
var2 = var1.length;

for(var3 = 0; var3 < var2; ++var3) {
var4 = var1[var3];
this.cp.getClass(dotToSlash(var4.getName()));
}

// 设置常量池为只读,生成字节码文件之前,不可以进行修改
this.cp.setReadOnly();
ByteArrayOutputStream var13 = new ByteArrayOutputStream();
DataOutputStream var14 = new DataOutputStream(var13);

// 完犊子,终于开始写出字节码文件了
try {
var14.writeInt(-889275714);
var14.writeShort(0);
var14.writeShort(49);
this.cp.write(var14);
var14.writeShort(this.accessFlags);
var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
var14.writeShort(this.interfaces.length);
Class[] var17 = this.interfaces;
int var18 = var17.length;

for(int var19 = 0; var19 < var18; ++var19) {
Class var22 = var17[var19];
var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
}

var14.writeShort(this.fields.size());
var15 = this.fields.iterator();

while(var15.hasNext()) {
ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next();
var20.write(var14);
}

var14.writeShort(this.methods.size());
var15 = this.methods.iterator();

while(var15.hasNext()) {
ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next();
var21.write(var14);
}

var14.writeShort(0);
return var13.toByteArray();
} catch (IOException var9) {
throw new InternalError("unexpected I/O Exception", var9);
}
}
}

// 13. 关于其中的addProxyMethod这个方法,这里我就不导读源码了,有需要的话大家自己去看看,基本就是通过反射去取关键信息
// 14. generateConstructor这个方法中,我们可以看出来,在生成代理类的构造方法的时候,参数是 InvocationHandler
// 15. 所以说,在JDK动态代理中,InvocationHandler 是核心,调用时真正走的是 InvocationHandler 的 invoke() 方法 -> java.lang.reflect.InvocationHandler#invoke(Object proxy, Method method, Object[] args) 根据传入的代理对象、方法、和参数决定具体调用的代理方法。

// 16. 大家可以通过上方设置参数saveGeneratedFiles将生成的代理类保存下来,然后反编译看看JDK动态代理生成的代码到底是什么样的
// 17. 好了,到这儿,JDK动态代理的源码分析就结束啦

6.2. CGLIB 动态代理的原理分析

  • 原理简介
1
2
3
4
5
6
7
// 1. 拿到被代理的类

// 2. 为 CGLIB 的 Enhancer 设置父类,及其需要回调的类

// 3. Enhancer 调用 create() 方法生成被代理对象,被代理对象会继承原先的类

// 4. 重写被代理的方法,同时加上 final 修饰符,不可再被重写,同时将增强的逻辑加入到代理方法前后
  • 源码剖析

有了 JDK 动态代理的经验,我们也先来看看 CGLIB 代理的对象有什么区别,同样在 这个位置 打个断点,如下图所示。果不其然,此时的 trainTicket 的引用地址依然奇怪,调试发现,是这个东西 TrainTicket$$EnhancerByCGLIB$$9d0422e9@681

image-20190824114026176

老规矩,我们来看下源码吧~

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
// trainTicket 是通过 getInstance() 获取的
// 1. 我们先看看 getInstance 主要做了什么操作
public Object getInstance(Class<?> clazz) {
// Enhancer 相当于 JDK 动态代理的 Proxy 类
Enhancer enhancer = new Enhancer();
// 设置动态生成的对象的父类为传进来的 被代理类
enhancer.setSuperclass(clazz);
// MethodInterceptor 继承 Callback 接口
enhancer.setCallback(this);
return enhancer.create();
}

// 2. 调用的是 net.sf.cglib.proxy.Enhancer#create() 创建类

/**
* Generate a new class if necessary and uses the specified
* callbacks (if any) to create a new object instance.
* Uses the no-arg constructor of the superclass.
* 如果有必要的话,就创建一个新的类,并根据指定的回调创建一个对象。
* 使用父类的无参构造方法创建对象
* @return a new instance
*/
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}

// 3. 发现 create() 方法,调用的是 createHelper() 方法 -> net.sf.cglib.proxy.Enhancer#createHelper()
private Object createHelper() {
// 判断 callbackTypes、filter 是否为空,同时对为空的条件做预处理
preValidate();
// 创建一个 Key
Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID);
this.currentKey = key;
// 调用父类 -> AbstractClassGenerator 的 create 方法
Object result = super.create(key);
return result;
}

// 4. 具体生成的逻辑走的是 net.sf.cglib.core.AbstractClassGenerator#create(Object key) 方法
protected Object create(Object key) {
try {
// 获取 ClassLoader
ClassLoader loader = getClassLoader();
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE;
AbstractClassGenerator.ClassLoaderData data = cache.get(loader);
if (data == null) {
// 保证线程安全
synchronized (AbstractClassGenerator.class) {
cache = CACHE;
data = cache.get(loader);
// 双重检查,确保线程安全
if (data == null) {
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> newCache = new WeakHashMap<ClassLoader, AbstractClassGenerator.ClassLoaderData>(cache);
data = new AbstractClassGenerator.ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
this.key = key;
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
// 具体创建对象的方法
return nextInstance(obj);
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}

// 5. 具体创建对象的方法是 nextInstance(),这个方法是个抽象方法,具体实现由子类 Enhancer 实现
abstract protected Object nextInstance(Object instance) throws Exception;

// 6. 我们现在看看 net.sf.cglib.proxy.Enhancer#nextInstance(Object instance) 方法
protected Object nextInstance(Object instance) {
Enhancer.EnhancerFactoryData data = (Enhancer.EnhancerFactoryData) instance;

if (classOnly) {
return data.generatedClass;
}

Class[] argumentTypes = this.argumentTypes;
Object[] arguments = this.arguments;
if (argumentTypes == null) {
argumentTypes = Constants.EMPTY_CLASS_ARRAY;
arguments = null;
}
return data.newInstance(argumentTypes, arguments, callbacks);
}
// 通过 data.newInstance(argumentTypes, arguments, callbacks) 返回具体对象,第一个参数为代理对象的构成器类型,第二个为代理对象构造方法参数,第三个为对应回调对象

/**
* Creates proxy instance for given argument types, and assigns the callbacks.
* Ideally, for each proxy class, just one set of argument types should be used,
* otherwise it would have to spend time on constructor lookup.
* 通过给定的参数类型,创建代理对象,同时分配回调。
* 理想情况下,每一个代理类,应该仅使用一组构造参数,否则,我们会花费很多的时间去找到对应的构造方法
* Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)},
* with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}"
*
* @see #createUsingReflection(Class)
* @param argumentTypes constructor argument types
* @param arguments constructor arguments
* @param callbacks callbacks to set for the new instance
* @return newly created proxy
*/
public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
setThreadCallbacks(callbacks);
try {
// Explicit reference equality is added here just in case Arrays.equals does not have one
if (primaryConstructorArgTypes == argumentTypes ||
Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
// If we have relevant Constructor instance at hand, just call it
// This skips "get constructors" machinery
return ReflectUtils.newInstance(primaryConstructor, arguments);
}
// Take a slow path if observing unexpected argument types
return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
} finally {
// clear thread callbacks to allow them to be gc'd
setThreadCallbacks(null);
}

}

// 到这里就生成了具体的对象
// 如果需要看到具体生成的字节码对象是啥,可以在调用 enhancer.create() 方法前,调用如下方法,可以在对应位置生成class文件,然后通过 jd-gui 这种反编译工具,就可以查看到具体代码啦~
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/yangkai.shen/Desktop/design-pattern/proxy/cglib/classes");

6.3. JDK 动态代理与 CGLIB 动态代理的区别

  1. JDK 动态代理生成的代理对象是实现了被代理对象的接口,CGLIB 动态代理生成的代理对象是继承了被代理对象。
  2. JDK 和CGLIB 都是在运行期生成字节码,JDK 是直接写 class 字节码,CGLIB 使用 ASM 框架写 class 字节码,CGLIB 代理实现更复杂,CGLIB 生成代理类的效率比 JDK 生成代理类效率低
  3. JDK调用代理方法,是通过反射机制调用,CGLIB是通过 FastClass机制直接调用方法,CGLIB 的被代理类执行效率比 JDK 的被代理类更高

6.3. Spring 中代理的选择原则

  1. 当Bean有实现接口时,Spring就会用JDK的动态代理。
  2. 当Bean没有实现接口时,Spring选择CGLib。
  3. Spring可以通过配置强制使用CGLib,只需在Spring的配置文件中加入如下代码:
1
<aop:aspectj-autoproxy proxy-target-class="true"/>

7. 完整代码地址

https://github.com/xkcoding/design-pattern/tree/master/src/main/java/com/xkcoding/design/pattern/structural/proxy

-------------本文结束  感谢您的阅读-------------
xkcoding wechat
欢迎来我的公众号「xkcoding小凯扣丁」逛逛
o(╯□╰)o 赞助一杯咖啡 ~~