代理模式
代理模式 - 大话设计模式
*每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。*
啊哈^ =.= :expressionless:
代理模式(Proxy)
基本概念
为其他对象提供一种代理 以控制对这个对象的访问(DP).
- 角色:
- 抽象角色: 用接口或者抽象类来实现(真实对象和代理对象的共同方法)
- 真实角色: 被代理的角色
- 代理角色: 代理真是角色 当然可以扩展其他业务
- 客户端: 具体操作 通过代理类访问代理对象
- 好处
- 可以使真实角色的业务更纯粹! 其他的公共业务和扩展业务不用考虑
- 实现了业务的分工 – 公共业务交给代理类
- 公共业务发生扩展时, 方便管理 (解耦)
- 静态代理缺点显然很明显: 代理只能服务一个类, 要是想代理很多类就要构建多个代理类
代理模式实现
代码部分
java
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 /* 公用接口类 */
public abstract class Subject {
public abstract void method(); // 定义 RealSubject和Proxy的公共方法
}
------------------------------------------------------------------------------
/* 代理类 */
public class Proxy extends Subject {
// 保存一个引用 使得代理可以访问实体 , 继承了同一个接口 所以可以实现真实实体的所有请求
private RealSubject realSubject; // 组合形式获取
// 在Spring框架中推荐使用 set方法来获取对象
public void method() {
if (realSubject == null) realSubject = new RealSubject();
realSubject.method(); // 调用真实的方法
// 当然可以加点东西
log();
}
// 扩展的业务
public void log() {
System.out.println("增加了日志方法");
}
}
------------------------------------------------------------------------------
/* 真实实体类 */
public class RealSubject extends Subject {
// 代理类代理的真实实体
public void method() {
System.out.println("实际的请求");
}
}
------------------------------------------------------------------------------
// 客户端
public static void main(String[] args) {
Proxy p = new Proxy();
p.method(); // 通过代理访问真实的方法
}
应用
- 远程代理
- 就是为一个对象在不同的地址空间提供据不同代表. 这样可以隐藏一个对象存在于不同地址空间的事实
- 虚拟代理
- 是根据需要创建开销很大的对象. 通过它存放实例化需要很长时间的对象.
- 安全代理
- 用来控制真实对象访问时的权限.
- 只能指引
- 是指当调用真实对象时, 代理处理另外一些事
动态代理
当然以上是静态代理的实现
静态代理缺点显然很明显: 代理只能服务一个类, 要是想代理很多类就要构建多个代理类
- 用反射机制构建动态代理
- 动态代理的代理类是动态生成的
- 动态代理分为两大类 – 基于接口 – 基于类
- 基于接口: JDK动态代理
- 基于类: cglib
- java字节码实现: javasist
- 需要 Proxy 和InvocationHandler 两个类来创建动态代理类
JDK动态代理: 和静态代理共同的是都要有真实实体类和接口
实体类和接口:
java
1
2
3
4
5
6
7
8
9
10
11
12
13 // 接口
public abstract interface Subject {
public abstract void method(); // 定义 RealSubject和需要被代理的方法方法
}
// 真实实体类
public class RealSubject implements Subject {
// 代理类代理的真实实体
public void method() {
System.out.println("实际的请求");
}
}动态代理实现:
InvocationHandler是个接口: 只有一个invoke方法 此方法在生成了一个 $Proxy.class 文件中被调用– (具体源码)[https://www.cnblogs.com/liuyun1995/p/8157098.html]
Proxy提供了创建动态代理类的静态方法
java
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 // 创建动态代理工具 -- 实现接口
public class MyProxyInvocationHandlerTemplate implements InvocationHandler {
private Object target; // 目标接口 -- 改为可复用的Obj类
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy() {
// 三个参数 1. 类加载器 2. 反射回去接口 3. InvocationHandler(就是本身)
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
A();// 扩展业务
Object o = method.invoke(target, args);
return o;
}
// 扩展业务
public void A() {
System.out.println("haha");
}
}客户端:
java
1
2
3
4
5
6
7
8
9
10
11
12 public static void main(String[] args) {
// p.method(); // 通过代理访问真实的方法
// 动态代理
// 实例动态代理工具
MyProxyInvocationHandlerTemplate template = new MyProxyInvocationHandlerTemplate();
// 实例真真实角色
RealSubject subject = new RealSubject();
template.setTarget(subject);
Subject sub = (Subject) template.getProxy();//创建代理类
sub.method();// 执行公共接口的方法
// 也会有附加业务的调用
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 大橘のBlog!
评论