结构型-代理模式
# 什么是代理模式
- 在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
- 日常开发过程中,通过代理模式,我们可以实现一些和业务无关的公共功能,例如方法执行时间、日志计算等。
# 为什么使用代理模式
- 添加一些特定功能,对原有的业务代码侵入性小。
- 更好的可扩展性
# 代理分类
静态代理
动态代理
- JDK 动态代理(基于接口)
- cglib 动态代理(采用继承)
- 无论使用 JDK 动态代理还是 cglib 动态代理,底层都是使用 asm 实现。
# 代理模式使用场景
- 可以实现实现一些非功能性需求:监控、统计、鉴权、限流、事务、幂等、日志。
- RPC 框架也可以看做一种代理模式,使得 RPC 服务的开发者也只需要开发业务逻辑,就像开发本地使用的函数一样,不需要关注跟客户端的交互细节。
- Spring AOP 底层的实现原理就是动态代理
- 基于 AOP 切面实现缓存功能
- 对于数据库操作事务控制
# 代理模式场景练习
需求:加入我们想统计某方法的执行时间。
- 第一种,最简单可以想到的就是直接在对应的代码前后使用时间计数做相减操作即可实现。
如果所在方法源码不允许修改,可以想到使用继承或者实现相同接口
一、继承原先的类,重写对应方法,添加时间统计功能
二、实现要代理的方法的对应的接口,但是此时同时需要接口对应其他方法,很繁琐。
如果此时不仅想统计执行时间,还想在执行前后打一些 log,如何实现代理的各种组合?继承?Decorator?
- 代理对象改成特定类型,然后进行不同的代理类之间的嵌套,类似装饰者模式
如果想让对应的代理行为功能和代理对象分离
- 使用 JDK 动态代理
- Cglib 动态代理
- spring AOP 代理
# 静态代理模式
public interface Movable {
void move();
}
public class Tank implements Movable {
@Override
public void move() {
System.out.println("Tank moving claclacla...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TankLogProxy implements Movable {
public TankLogProxy(Movable movable) {
this.movable = movable;
}
private final Movable movable;
@Override
public void move() {
System.out.println("start moving.....");
movable.move();
System.out.println("end moving...");
}
}
public class TankTimeProxy implements Movable {
public TankTimeProxy(Movable movable) {
this.movable = movable;
}
private final Movable movable;
@Override
public void move() {
long start = System.currentTimeMillis();
movable.move();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
}
public class Main {
public static void main(String[] args) {
Tank tank = new Tank();
TankTimeProxy tankTimeProxy = new TankTimeProxy(tank);
TankLogProxy tankLogProxy = new TankLogProxy(tankTimeProxy);
tankLogProxy.move();
}
}
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
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
# JDK 动态代理
public interface Movable {
void move();
}
public class Tank implements Movable {
@Override
public void move() {
System.out.println("Tank moving claclacla...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TimeProxy implements InvocationHandler {
public TimeProxy(Movable movable) {
this.movable = movable;
}
Movable movable;
public void before() {
System.out.println("Before");
}
public void after() {
System.out.println("After");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object object = method.invoke(movable, args);
after();
return object;
}
}
public class Main {
public static void main(String[] args) {
Tank tank = new Tank();
System.getProperties().setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
Movable movable = (Movable) Proxy.newProxyInstance(Tank.class.getClassLoader(),
new Class[]{Movable.class},
new TimeProxy(tank)
);
movable.move();
}
}
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
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
# Java 动态代理调用流程
# Cglib 动态代理
public class Tank {
public void move() {
System.out.println("Tank moving claclacla...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TimeMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(o.getClass().getSuperclass().getName());
System.out.println("Before");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("After");
return result;
}
}
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Tank.class);
enhancer.setCallback(new TimeMethodInterceptor());
Tank tank = (Tank) enhancer.create();
tank.move();
}
}
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
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
# SpringAop 动态代理
public class Tank {
public void move() {
System.out.println("Tank moving claclacla...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TankTimeProxy {
public void before() {
System.out.println("before");
}
public void after() {
System.out.println("after");
}
}
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app.xml");
Tank tank = (Tank) context.getBean("tank");
tank.move();
}
}
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
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
# app.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<bean id="tank" class="com.holddie.design.proxy.springAop.v1Xml.Tank"/>
<bean id="timeProxy" class="com.holddie.design.proxy.springAop.v1Xml.TankTimeProxy"/>
<aop:config>
<aop:aspect id="time" ref="timeProxy">
<aop:pointcut id="tankMoving"
expression="execution(void com.holddie.design.proxy.springAop.v1Xml.Tank.move())"/>
<aop:before method="before" pointcut-ref="tankMoving"/>
<aop:after method="after" pointcut-ref="tankMoving"/>
</aop:aspect>
</aop:config>
</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
上次更新: 2020/09/08, 15:09:00