代理模式(Proxy Pattern)是一种结构型设计模式
,通过引入代理对象控制对原始对象的访问
,在不修改原始类的前提下增强其功能。代理模式的核心是间接访问
,常用于权限控制、延迟加载、日志记录等场景。
核心思想
- 中介隔离:代理对象作为客户端和真实对象之间的中介,管理对真实对象的访问。
- 职责分离:将非核心逻辑(如权限校验、日志)从真实对象中剥离,提升代码可维护性。
- 透明性:客户端无需感知代理存在,代理与真实对象实现相同接口。
模式结构
角色 | 职责 |
---|---|
抽象主题(Subject) | 定义真实对象和代理对象的共同接口,客户端依赖此接口 |
真实主题(Real Subject) | 实现核心业务逻辑的具体类,是代理最终调用的对象 |
代理(Proxy) | 实现抽象主题接口,持有真实主题的引用,负责预处理、过滤或后置处理请求 |
实现方式
1. 静态代理(手动编码代理类)
示例:文件访问保护代理
// 抽象主题
interface FileAccess {
void readFile(String filename);
}
// 真实主题
class RealFileAccess implements FileAccess {
@Override
public void readFile(String filename) {
System.out.println("读取文件内容:" + filename);
}
}
// 代理类(添加权限校验)
class FileAccessProxy implements FileAccess {
private RealFileAccess realFileAccess;
private String userRole;
public FileAccessProxy(String userRole) {
this.userRole = userRole;
}
@Override
public void readFile(String filename) {
if (!"admin".equals(userRole)) {
System.out.println("无权限访问文件!");
return;
}
if (realFileAccess == null) {
realFileAccess = new RealFileAccess(); // 延迟初始化
}
realFileAccess.readFile(filename);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
FileAccess proxy = new FileAccessProxy("user");
proxy.readFile("secret.txt"); // 输出:无权限访问文件!
}
}
2. 动态代理(运行时生成代理类)
JDK动态代理示例(基于接口)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 抽象主题
interface Database {
void query(String sql);
}
// 真实主题
class RealDatabase implements Database {
@Override
public void query(String sql) {
System.out.println("执行查询:" + sql);
}
}
// 代理处理器(添加日志)
class LoggingHandler implements InvocationHandler {
private Object target;
public LoggingHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("记录日志:执行方法 " + method.getName());
return method.invoke(target, args);
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Database realDb = new RealDatabase();
Database proxy = (Database) Proxy.newProxyInstance(
realDb.getClass().getClassLoader(),
realDb.getClass().getInterfaces(),
new LoggingHandler(realDb)
);
proxy.query("SELECT * FROM users");
// 输出:记录日志:执行方法 query → 执行查询:SELECT * FROM users
}
}
CGLIB动态代理示例(基于类,无需接口)
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class UserService {
public void save() {
System.out.println("保存用户数据");
}
}
class TransactionInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("开启事务");
Object result = proxy.invokeSuper(obj, args);
System.out.println("提交事务");
return result;
}
}
public class Client {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new TransactionInterceptor());
UserService proxy = (UserService) enhancer.create();
proxy.save();
// 输出:开启事务 → 保存用户数据 → 提交事务
}
}
代理模式变体
代理类型 | 特点 |
---|---|
远程代理 | 隐藏远程对象通信细节(如HTTP/RPC调用),客户端像调用本地对象一样操作 |
虚拟代理 | 延迟大对象的创建,直到真正需要时(如图片加载、大文件处理) |
保护代理 | 控制访问权限,根据身份决定是否允许操作 |
缓存代理 | 缓存请求结果,减少重复计算或网络请求 |
同步代理 | 为多线程环境提供线程安全访问控制 |
优缺点分析
优点
- 职责清晰:分离核心功能与非核心逻辑(如安全、日志)。
- 高扩展性:通过代理类灵活增强功能,符合开闭原则。
- 保护真实对象:限制直接访问,提升系统安全性。
缺点
- 增加系统复杂度:引入代理层可能使代码结构复杂化。
- 性能损耗:动态代理通过反射实现,调用速度较慢(可通过缓存优化)。
- 静态代理类冗余:需为每个真实类编写代理类,代码量大。
应用场景
适用场景
- 远程代理:为远程服务(如RPC接口)提供本地代理,隐藏网络通信细节。
- 虚拟代理:延迟高开销对象的创建(如图片懒加载)。
- 保护代理:控制对敏感对象的访问权限。
- 智能引用代理:添加额外操作(如引用计数、对象状态监控)。
- 缓存代理:缓存请求结果,减少重复计算或网络开销。
实际应用
- Spring AOP:通过动态代理实现日志、事务等切面功能。
- MyBatis Mapper接口:动态代理生成数据库操作实现类。
- RPC框架(如Dubbo):客户端通过代理调用远程服务。
- Hibernate延迟加载:虚拟代理延迟数据库查询。
- Java安全管理器:保护代理控制对系统资源的访问。
与其他模式对比
模式 | 对比点 |
---|---|
装饰器模式 | 关注增强功能,透明性更高;代理模式强调访问控制,可能隐藏真实对象 |
适配器模式 | 解决接口不兼容问题;代理模式保持接口一致,仅控制访问流程 |
外观模式 | 封装多个子系统简化接口;代理模式控制单个对象的访问 |
使用建议
- 优先选择动态代理:减少重复代码,但需注意性能影响。
- 明确代理职责:避免代理类承担过多无关逻辑,保持单一职责。
- 结合其他模式:如与工厂模式结合管理代理对象创建。
总结
代理模式通过间接访问
机制,在保护真实对象的同时扩展其能力,是系统解耦和功能增强的常用手段。在需要控制访问权限、优化资源使用或添加横切关注点(如日志、事务)的场景中,合理运用代理模式能显著提升代码的灵活性和可维护性。