代理模式(Proxy Pattern)学习笔记
1. 模式定义
结构型设计模式,为其他对象提供一种代理以控制对这个对象的访问。通过引入代理对象,在客户端和目标对象之间起到中介作用。
2. 适用场景
✅ 远程代理(Remote Proxy):为不同地址空间的对象提供代理
✅ 虚拟代理(Virtual Proxy):延迟创建开销大的对象
✅ 保护代理(Protection Proxy):控制不同权限的访问
✅ 智能引用代理(Smart Reference):添加额外操作(如引用计数)
✅ AOP实现、日志记录、事务管理等横切关注点
3. 模式结构
4. 核心角色
角色 | 说明 |
---|---|
Subject | 抽象主题接口,声明真实主题和代理的共同接口 |
RealSubject | 真实主题类,定义代理所代表的真实对象 |
Proxy | 代理类,持有真实主题的引用,提供与真实主题相同的接口 |
Client | 客户端,通过代理对象间接访问真实主题 |
5. 实现方式对比
类型 | 实现方式 | 优点 | 缺点 |
---|---|---|---|
静态代理 | 手动创建代理类 | 简单直观 | 类膨胀,接口修改需要同步维护 |
JDK动态代理 | 基于接口,使用Proxy 和InvocationHandler | 无需实现大量代理类 | 只能代理接口 |
CGLIB代理 | 基于字节码生成子类 | 可以代理普通类 | 无法代理final类和方法 |
6. 代码示例
6.1 静态代理示例
// 抽象主题
interface Image {
void display();
}
// 真实主题
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("加载图片: " + filename);
}
@Override
public void display() {
System.out.println("显示图片: " + filename);
}
}
// 代理类
class ProxyImage implements Image {
private RealImage realImage;
private String filename;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
image.display(); // 真实对象被创建
image.display(); // 直接使用已创建对象
}
}
6.2 JDK动态代理示例
import java.lang.reflect.*;
// 抽象主题
interface UserService {
void addUser(String name);
}
// 真实主题
class UserServiceImpl implements UserService {
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
}
// 代理处理器
class LogHandler implements InvocationHandler {
private Object target;
public LogHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("[日志] 方法调用: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("[日志] 方法完成: " + method.getName());
return result;
}
}
// 客户端
public class Client {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
realService.getClass().getInterfaces(),
new LogHandler(realService)
);
proxy.addUser("张三");
}
}
7. 模式变种
- 远程代理:处理网络通信细节(如RPC调用)
- 虚拟代理:延迟加载大资源对象
- 防火墙代理:控制网络资源的访问
- 同步代理:提供多线程安全访问
- 缓存代理:为开销大的运算结果提供缓存
8. 优缺点分析
✔️ 优点:
- 职责清晰,高扩展性
- 保护真实对象,控制访问细节
- 降低系统耦合度
- 支持横切关注点集中处理
❌ 缺点:
- 增加系统复杂度
- 动态代理使用反射影响性能
- 代理模式可能造成请求处理变慢
9. 相关模式对比
模式 | 目的 | 关键区别 |
---|---|---|
装饰者模式 | 增强功能 | 关注对象功能的增强 |
适配器模式 | 接口转换 | 主要解决接口不兼容问题 |
外观模式 | 简化接口 | 组合多个子系统接口 |
10. 实际应用案例
- Spring AOP的动态代理实现
- MyBatis的Mapper接口代理
- Java RMI远程方法调用
- Hibernate的延迟加载(Lazy Loading)
- Servlet的FilterChain
- Retrofit的网络请求接口
11. 最佳实践建议
- 优先使用JDK动态代理(标准库支持)
- 需要代理普通类时使用CGLIB
- 注意代理方法的性能影响
- 避免过度使用导致系统复杂性增加
- 使用代理模式实现横切关注点时,结合AOP框架
- 对关键业务方法添加访问日志时使用保护代理
🔑 记忆技巧:把代理模式想象成明星的经纪人,客户端(粉丝)通过经纪人(代理)与明星(真实对象)进行互动。