Java 基础 - 代理模式
# 代理的概念
代理中有两个核心角色:代理对象和被代理对象。通常是被代理对象那个委托代理对象替自己完成某项工作,如明星委托经纪人安排工作日程、企业委托猎头替自己招人、客户委托房屋中介替自己找心仪的房子。
代理模式的原理是使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。使用代理的前提是代理对象和被代理对象实现同一个接口中的方法。
代理的应用场景:
- 安全代理:屏蔽对真实角色的直接访问;
- 远程代理:通过代理类处理远程方法调用;
- 延迟加载:先加载轻量级的代理对象,真正需要的时候再加载真实对象。
JDK中的代理主要分为静态代理和动态代理:
- 静态代理指的是代理类和被代理类在编译期间就已经显式确定,静态代理不利于程序的扩展。
- 动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。
# 静态代理
package com.sqlboy.reflect;
public class StaticProxyTest {
public static void main(String[] args) {
// 被代理对象
Customer customer1 = new Customer("找房子");
// 代理对象
HouseWorker houseWorker = new HouseWorker(customer1);
// 代理对象通过自己的方法,间接调用了被代理对象的方法
houseWorker.action();
// 被代理对象
Customer customer2 = new Customer("买车");
// 代理对象
CarWorker carWorker = new CarWorker(customer2);
// 代理对象通过自己的方法,间接调用了被代理对象的方法
carWorker.action();
}
}
/**
* 抽象代理行为
*/
interface Worker {
void action();
}
/**
* 代理对象
*/
class HouseWorker implements Worker {
// 被代理对象
Customer customer;
HouseWorker(Customer customer) {
this.customer = customer;
}
@Override
public void action() {
customer.action();
System.out.println("我是房屋中介,我帮你去完成");
}
}
class CarWorker implements Worker {
// 被代理对象
Customer customer;
CarWorker(Customer customer) {
this.customer = customer;
}
@Override
public void action() {
customer.action();
System.out.println("我是汽车销售,我替你去完成");
}
}
class Customer implements Worker {
String demand;
Customer(String demand) {
this.demand = demand;
}
@Override
public void action() {
System.out.println("我是雇主,我需要" + demand);
}
}
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
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
输出:
我是雇主,我需要找房子
我是房屋中介,我帮你去完成
我是雇主,我需要买车
我是汽车销售,我替你去完成
1
2
3
4
2
3
4
静态代理的特点是在程序编译期间就需要指定代理对象和被代理对象,可以看到如果有不同的需求,就需要定义不同的代理类和代理对象,不利于扩展。
# 动态代理
动态代理的优势是抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。使用动态代理的核心步骤是:
- 根据加载的被代理类动态地创建一个代理类的对象;
- 调用代理类的某个方法时,动态地调用被代理类中的同名方法。
Java 中提供的 Proxy 类用来专门完成动态代理操作,它是所有动态代理类的父类。Proxy 中的核心方法:
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
:创建 一个动态代理类所对应的 Class 对象。static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
:直接创建一个动态代理对象。
示例:
package com.sqlboy.reflect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String[] args) {
// 被代理对象1需要找房
Customer customer1 = new Customer("找房子");
// 代理工厂动态生成代理对象,替客户完成
Worker proxyInstance1 = (Worker) ProxyFactory.getProxyInstance(customer1);
// 代理对象通过调用自己的方法,间接调用了被代理对象的方法,知道了对方的需求
proxyInstance1.action();
Customer customer2 = new Customer("买车");
Worker proxyInstance2 = (Worker) ProxyFactory.getProxyInstance(customer2);
proxyInstance2.action();
}
}
/**
* 代理工厂
*/
class ProxyFactory {
/**
* 获取代理对象实例
*
* @param obj 被代理对象
* @return
*/
public static Object getProxyInstance(Object obj) {
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
// 根据加载的被代理类动态地创建一个代理类的对象
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
}
class MyInvocationHandler implements InvocationHandler {
// 被代理对象
private Object obj;
// 为被代理对象赋值
public void bind(Object obj) {
this.obj = obj;
}
// 当通过代理对象调用某个方法a时,就会自动调用此方法
// 所以可以将被代理对象要执行的功能a定义在此方法中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// method为代理类对象的方法
Object invokeResult = method.invoke(obj, args);
System.out.println("我是代理对象,我替你去完成");
return invokeResult;
}
}
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
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
输出:
我是雇主,我需要找房子
我是代理对象,我替你去完成
我是雇主,我需要买车
我是代理对象,我替你去完成
1
2
3
4
2
3
4
在上面的动态代理示例中,并没有明确定义代理对象是汽车销售还是房产中介,而是通过代理工程根据客户种类动态生成的,如果有新的客户需求(如招聘、理财等),代理工厂依然可以动态创建一个代理对象出来。
上次更新: 2023/11/01, 03:11:44