📖 介绍
代理模式是一种结构型模式。
代理模式是为了方便访问某些资源,使对象类更加易用。为其他对象提供一种代理控制这个对象的访问。
常见的场景:
🔖 买火车票不一定要去火车站,也可以去代售点。
🔖 Windows 中的快捷方式,Linux 中的软链接。
🔖 Spring AOP。
🔖 常见的 ORM 框架,只要定义相关的接口,而不需要写实现类,就可以对 XML 或注解中的 SQL 语句进行增删改查操作。
🔖 一些中间件如 RPC 框架,在拿到 jar 包中对接口的描述后,中间件会字服务启动时,生成对应的代理类。当调用接口时,实际上是通过代理类发出的 Socket 信息。
🎈 实现方式
🎗️ 方法(1):抽取接口,代理对象和服务对象实现同一个接口。
🎗️ 方法(2):并不是所有情况都能抽取接口(如代码改动很大、不能修改服务类),可以将代理类作为服务类的子类,让代理类继承服务类的所有接口。
🎗️ 创建代理类,代理类中必须包含一个服务类的成员变量,负责服务类的整个生命周期。(可通过构造函数传入,或在内部创建)
🎗️ 根据需求实现代理方法。大部分情况下,代理方法会调用服务对象的同名方法。
🚦 可考虑设计选项:
构建一个方法,用于客户端判断获得的是代理对象,还是实际服务对象。
代理对象中服务对象可以考虑延迟初始化。
☕ Java 中的动态代理
在 Java 标准库中,提供了动态代理功能,允许在运行期动态创建一个接口的实例。其实就是 JVM 在运行期间,动态创建 class 字节码并加载的过程。
动态代理通过 Proxy
创建代理对象,然后将接口方法“代理”给 InvocationHandler
。
|
|
|
|
在运行期间创建一个 interface
实例的步骤:
定义一个
InvocationHandler
实例,负责实现接口的方法调用通过
Proxy.newProxyInstance()
创建interface
实例ClassLoader loader
类加载器(如当前类的类加载器:CurrentProxy.class.getClassLoader()
)Class<?>[] interfaces
需要实现的接口的数组(代理的对象是实现了哪个接口)InvocationHandler h
用来处理接口方法调用的InvocationHandler
实例(生成的代理对象中的代理方法,需要做什么)
返回一个
Object
,可强制转型为接口。
|
|
🎲 适合场景
🎨 延迟初始化。将对象的初始化延迟到真正有需要的时候。
🎨 访问控制。代理可仅在客户端凭据满足要求时将请求传递给服务对象。
🎨 本地执行远程服务 (远程代理)。适用于服务对象位于远程服务器上的情形。代理通过网络传递客户端请求,负责处理所有与网络相关的复杂细节。
🎨 记录日志请求(日志记录代理)。如需要保存对于服务对象的请求历史记录时。
🎨 缓存请求结果(缓存代理)。 如可对重复请求所需的相同结果进行缓存。
🔗 参考
- https://refactoringguru.cn/design-patterns/proxy
- https://bugstack.cn/md/develop/design-pattern/2020-06-16-%E9%87%8D%E5%AD%A6%20Java%20%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%8A%E5%AE%9E%E6%88%98%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F%E3%80%8B.html
- https://www.runoob.com/design-pattern/proxy-pattern.html
- https://www.liaoxuefeng.com/wiki/1252599548343744/1264804593397984