代理模式

1、理论介绍

① 概念

代理模式是二十三种设计模式中的一种,属于结构型模式

它的作用就是通过提供一个代理类,让我们再调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰。

② 相关术语

  • 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。
  • 目标:被代理“套用”了非核心逻辑代码的类、对象、方法。

2、代码实现

① 情景设定

[1]创建计算器接口

1
2
3
4
5
6
7
8
9
10
11
public interface ICalculator {

int add(int i, int j);

int sub(int i, int j);

int mul(int i, int j);

int div(int i, int j);

}

[2]创建计算器接口的实现类

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
public class CalculatorImpl implements ICalculator {
@Override
public int add(int i, int j) {

int result = i + j;

return result;
}

@Override
public int sub(int i, int j) {

int result = i - j;

return result;
}

@Override
public int mul(int i, int j) {

int result = i * j;

return result;
}

@Override
public int div(int i, int j) {

int result = i / j;

return result;
}
}

② 使用动态代理

效果:假设我们针对日志功能进行代理,那么这个类专门负责给其他类增加日志的功能,不管目标类是什么,使用这个代理类之后都能够增加日志功能。

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
public class LogDynamicProxyFactory {

// 维护被代理的目标对象,由于我们希望这个类有通用性,所以这里使用Object类型
private Object target;

// 声明有参的构造器,让我们创建代理类的对象时,可以把目标对象给传进来
public LogDynamicProxyFactory(Object target) {
this.target = target;
}

// 声明一个专门的方法来返回代理对象
public Object getProxyObject() {

// 把被代理的目标对象的类加载到内存的类加载器
ClassLoader classLoader = this.target.getClass().getClassLoader();

// 被代理的目标对象所实现的所有接口组成的数组
Class<?>[] interfaces = this.target.getClass().getInterfaces();

// 创建InvocationHandler对象:调用目标对象的目标方法并且附加代理逻辑的代码
InvocationHandler invocationHandler = (

// 代理对象本身(没有用到)
Object proxy,

// 要调用的目标方法
Method method,

// 调用目标方法时要传入的参数
Object[] args) -> {

// 声明一个变量,用来接收目标方法的返回值
Object targetMethodReturnValue = null;
// 获取目标方法的名称
String methodName = method.getName();
// 为了直接打印时能够看到数组中的数据,把数组转换为List集合
List<Object> argList = Arrays.asList(args);

try {
// 代理逻辑:目标操作前代码
System.out.println("[代理]" + methodName + "方法开始执行,参数列表是:" + argList);

// 将目标方法设置为可以访问
method.setAccessible(true);

// 核心逻辑:调用被代理的目标对象的目标方法【理解整个代理类的第二个核心】
// public Object invoke(Object obj, Object... args)
// obj参数:调用目标方法的对象
// args参数:调用目标方法时需要传入的参数
targetMethodReturnValue = method.invoke(target, args);

// 代理逻辑:目标操作成功后代码
System.out.println("[代理]" + methodName + "方法成功结束,执行结果是:" + targetMethodReturnValue);
} catch (Exception e) {
e.printStackTrace();

// 代理逻辑:目标操作抛异常结束代码
System.out.println("[代理]" + methodName + "方法异常结束,抛出异常是:" + e);

} finally {

// 代理逻辑:目标操作最终结束代码
System.out.println("[代理]" + methodName + "方法最终结束");

}

// 当前方法作为代理方法,需要将目标方法执行完成后返回的返回值,返回给外界的调用者
return targetMethodReturnValue;
};

// 利用前面准备好的资源,创建代理对象的实例并返回【理解整个代理类的第一个核心】
return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
}

⑤ 测试方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void testDynamicProxy() {
// 1.创建被代理的目标对象
ICalculator target = new CalculatorImpl();

// 2.创建生产代理对象的工厂对象
LogDynamicProxyFactory factory = new LogDynamicProxyFactory(target);

// 3.获取目标对象的代理对象
ICalculator proxyObject = (ICalculator) factory.getProxyObject();

// 4.通过代理对象间接调用目标对象的方法
int addResult = proxyObject.add(6, 3);
System.out.println("[测试]addResult = " + addResult);

int subReult = proxyObject.sub(6, 3);
System.out.println("[测试]subReult = " + subReult);

int mulResult = proxyObject.mul(6, 3);
System.out.println("[测试]mulResult = " + mulResult);

int divResult = proxyObject.div(6, 0);
System.out.println("[测试]divResult = " + divResult);
}