代理模式(Proxy Pattern)
半塘 2024/3/28 Java进阶
为其他对象提供一种代理以控制对这个对象的访问。本质就是通过A来访问B的方法。
# 1、代理模式案例
华为手机打电话,但我想在前后记录时间,但不改变原来的模式,就可以通过代理方式,用代理对象来调用call方法,这样在调用前后就可以做操作了。
public interface Phone {
void call();
}
public class HuaweiPhone implements Phone{
@Override
public void call() {
System.out.println("华为打电话");
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
public class HuaweiProxy implements Phone{
private HuaweiPhone huaweiPhone;
public HuaweiProxy(HuaweiPhone huaweiPhone) {
this.huaweiPhone = huaweiPhone;
}
@Override
public void call() {
System.out.println("开始打电话:"+ LocalTime.now());
huaweiPhone.call();
System.out.println("结束打电话:"+ LocalTime.now());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ClientTest {
public static void main(String[] args) {
HuaweiProxy proxy = new HuaweiProxy(new HuaweiPhone());
proxy.call();
}
}
/**
* 输出结果
* 开始打电话:13:34:45.351
* 华为打电话
* 结束打电话:13:34:45.352
* /
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 2、JDK动态代理案例
上面代理的方式太多麻烦,每次都得新建一个类,JDK提供了一种动态代理的方式,不过只能为接口创建动态代理。
public interface Phone {
void call();
}
public class HuaweiPhone implements Phone{
@Override
public void call() {
System.out.println("华为打电话");
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
public static void main(String[] args) throws NoSuchMethodException,
InvocationTargetException, InstantiationException, IllegalAccessException {
// 创建原对象
Phone phone = new HuaweiPhone();
// 创建动态代理对象,底层是反射机制,newProxyInstance(接口实现类,代理的接口,InvocationHandler实例)
Phone phoneProxy=(Phone) Proxy.newProxyInstance(HuaweiPhone.class.getClassLoader(),
HuaweiPhone.class.getInterfaces(),
new InvocationHandler() {
/**
* proxy:被代理对象的引用,系统会自动创建被代理对象的一个映射
* method:被代理对象的方法
* args: 被代理对象方法的参数
* 返回值是被代理对象执行后的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//被代理对象方法的执行,并获得返回值
Object result=null;
System.out.println("开始打电话:"+ LocalTime.now());
result = method.invoke(phone,args);
System.out.println("结束打电话:"+ LocalTime.now());
return result;
}
});
// 只打电话
phone.call();
// 通过代理对象来调用打电话,能够执行代理内部逻辑
phoneProxy.call();
}
/**
* 输出结果:
* 华为打电话
* 开始打电话:14:00:13.008
* 华为打电话
* 结束打电话:14:00:13.008
* /
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
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
# 3、CGLIB动态代理案例
不仅仅可以为接口,也可以为类创建动态代理
public interface Phone {
void call();
}
public class HuaweiPhone implements Phone{
@Override
public void call() {
System.out.println("华为打电话");
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
//1.创建Enhancer对象
Enhancer enhancer = new Enhancer();
//2.通过setSuperclass来设置父类型,即需要给哪个类创建代理类
enhancer.setSuperclass(HuaweiPhone.class);
//3.设置回调,需要Callback接口,此处我们实现的是MethodInterceptor,是Callback的子接口
//当调用代理对象的任何方法时,都会被MethodInterceptor的invoke方法处理
enhancer.setCallback(new MethodInterceptor() {
/**
* Object o:代理对象
* Method method:被代理的类的方法,即HuaweiPhone中的方法
* Object[] objects:调用方法传递的参数
* MethodProxy methodProxy:方法代理对象
*/
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
System.out.println("开始打电话:"+ LocalTime.now());
Object result = methodProxy.invokeSuper(o,objects);
System.out.println("结束打电话:"+ LocalTime.now());
return result;
}
});
//4.获取代理对象:通过enhancer.create()获取代理对象,返回值是Object类型,需强转
HuaweiPhone proxy = (HuaweiPhone) enhancer.create();
//5.调用代理对象的方法
proxy.call();
}
/**
* 输出结果:
* 开始打电话:14:12:13.214
* 华为打电话
* 结束打电话:14:12:13.243
* /
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
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
动态代理最佳体现,Spring的AOP实现