代理模式(Proxy Pattern)
# 代理模式(Proxy Pattern)
代理模式 (Proxy Pattern) , 给某一个对象提供一个代理,并由代理对象控制对原对象的引用,对象结构型模式。这种也是静态代理

代理模式包含如下角色:
Subject: 抽象主体角色 (抽象类或接口)
Proxy: 代理主体角色 (代理对象类)
RealSubject: 真实主体角色 (被代理对象类)
# 静态代理
代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象。这样做的好处 是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
- 静态代理就是装饰器模式
- 装饰器模式是代理模式的一种
Subject: 抽象主体角色 (抽象类或接口)
/**
* 抽象主体 被代理角色
*/
public interface ManTikTok {
void tiktok();
}
1
2
3
4
5
6
2
3
4
5
6
Proxy: 代理主体角色 (代理对象类)
/**
* 代理一般和被代理对象属于同一个接口
* 静态代理就是装饰器模式
* 装饰器模式是代理模式的一种
*/
public class TiktokProxy implements ManTikTok{
//被代理对象
private MiTikTok miTikTok;
public TiktokProxy(MiTikTok miTikTok) {
this.miTikTok = miTikTok;
}
@Override
public void tiktok() {
System.out.println("增强功能");
miTikTok.tiktok();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
RealSubject: 真实主体角色 (被代理对象类)
/**
* subject 主体
*
*/
public class MiTikTok implements ManTikTok{
@Override
public void tiktok() {
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) {
TiktokProxy tiktokProxy = new TiktokProxy(new MiTikTok());
tiktokProxy.tiktok();
}
1
2
3
4
2
3
4
# JDK 动态代理
利用 JDK 动态代理 反射增强
Subject: 抽象主体角色 (抽象类或接口)
/**
* 抽象主体 被代理角色
*/
public interface ManTikTok {
void tiktok();
}
1
2
3
4
5
6
2
3
4
5
6
public interface SellTiktok {
void send();
}
1
2
3
2
3
Proxy: 代理主体角色 (代理对象类)
public class JdkTiktokProxy<T> implements InvocationHandler {
private T target;
//接受被代理对象
public JdkTiktokProxy(T target) {
this.target = target;
}
/**
* 获取被代理对象的 代理对象
*
* @param t
* @param <T>
* @return
*/
public static <T> T getProxy(T t) {
/**
* ClassLoader loader, 当前被代理的类加载器
* Class<?>[] interfaces, 当前被代理对象所实现的所有接口 必须要有接口 如果无则会报异常 代理对象无法创建
* InvocationHandler h 当前被代理对象执行目标方法的时候我们使用h可以定义拦截增强方法
*/
Object o = Proxy.newProxyInstance(t.getClass().getClassLoader(),
t.getClass().getInterfaces(),
new JdkTiktokProxy<>(t)
);
return (T) o;
}
/**
* 定义目标方法的拦截逻辑:每个方法都会进来的
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//反射执行
System.out.println("被代理对象原身方法被执行");
Object invoke = method.invoke(target, args);
System.out.println("返回值" + invoke);
return invoke;
}
}
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
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
RealSubject: 真实主体角色 (被代理对象类)
/**
* subject 主体
*
*/
public class MiTikTok implements ManTikTok,SellTiktok {
@Override
public void tiktok() {
System.out.println("雷军正在直播");
}
@Override
public void send() {
System.out.println("卖货 只要999");
}
public void self(){
System.out.println("自身方法");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
测试方法
/**
* 动态代理模式
* JDK要求被代理对象必须要有接口
*
*/
public class MainTest {
public static void main(String[] args) {
ManTikTok miTikTok = new MiTikTok();
ManTikTok proxy = JdkTiktokProxy.getProxy(miTikTok);
proxy.tiktok();
System.out.println("---------------");
SellTiktok sellTikTok = (SellTiktok)miTikTok;
SellTiktok proxy1 = JdkTiktokProxy.getProxy(sellTikTok);
proxy1.send(); //只能调用某个接口的实现方法
System.out.println("---------------");
MiTikTok miTikTok1 = (MiTikTok) miTikTok;
//无法代理对象本类自己的方法 proxy只能转成接口类
// MiTikTok proxy2 = JdkTiktokProxy.getProxy(miTikTok1);
miTikTok1.self();
System.out.println(Arrays.asList(miTikTok1.getClass().getInterfaces()));
}
}
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
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
# cglib 动态代理
在 pom.xml 导入 cglib 依赖
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
</dependencies>
1
2
3
4
5
6
7
2
3
4
5
6
7
cglib 不依赖于接口代理反射,他会根据代理对象去继承一个新类,从而代理这个对象。
Proxy: 代理主体角色 (代理对象类)
public class CglibProxy {
//为任意对象创建代理
public static <T> T crateProxy(T t) {
//1. 创建一个增强器
Enhancer enhancer = new Enhancer();
//2.设置增强哪个类的功能 增强器为这个类动态创建一个子类
enhancer.setSuperclass(t.getClass());
//3.设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method //为了能获取原方法的一些原数据信息
, Object[] objects, MethodProxy methodProxy) throws Throwable {
//编写拦截逻辑
System.out.println("cglib 代理");
//当前方法的信息
// method.getAnnotatedReturnType();
//目标方法进行执行 原对象的方法
Object invoke = methodProxy.invokeSuper(o, objects);
return invoke;
}
});
//创建代理对象
Object o = enhancer.create();
return (T)o;
}
}
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
RealSubject: 真实主体角色 (被代理对象类)
/**
* subject 主体
*
*/
public class MiTikTok {
public void self(){
System.out.println("自身方法");
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
测试类
public class CglibTest {
public static void main(String[] args) {
//原对象都不用new
MiTikTok miTikTok = new MiTikTok();
MiTikTok proxy = CglibProxy.crateProxy(miTikTok);
proxy.self();
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 应用场景
MyBatis 的 mapper 到底是什么?怎么生成的?
动态代理
UserMapper、CityMapper,mybatis 帮我们写实现 MapperProxy
Alibaba Seata 的 DataSourceProxy 是什么?
DruidDataSource 存在的 Proxy 模式
- 监控链...
几种常见的代理模式介绍 — 几种变体
- 防火墙代理:内网通过代理穿透防火墙,实现对公网的访问。
- 缓存代理:比如当请求图片文件等资源时,先到缓存代理取,如果取到资源则 ok, 如果取不到资源,再到公网或者数据 库取,然后缓存。
- 远程代理:远程对象的本地代表,通过它可以把远程对象当本地对象来调用。远程代理通过网络和真正的远程对象沟通信 息。
- 同步代理:主要使用在多线程编程中,完成多线程间同步工作
# 区别 - 装饰器、代理
装饰器、代理:
- 装饰器和代理之间的区别很细微,可以认为装饰器是代理的一个子集。
- 静态代理就是装饰器的方式
编辑 (opens new window)
上次更新: 2023/12/13, 06:06:02