代理模式详解
一、代理模式概述
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,可以在不改变原始类代码的情况下增加额外功能。
核心特点
- 控制访问:控制对目标对象的访问权限
- 功能增强:在不修改目标对象的前提下增加额外功能
- 解耦:客户端与目标对象解耦
- 透明性:代理对象与目标对象实现相同接口
二、代理模式的类型
1. 静态代理
基本实现
// 抽象主题接口
public interface Subject {
void request();
}
// 真实主题
public class RealSubject implements Subject {
public void request() {
System.out.println("真实主题处理请求");
}
}
// 代理类
public class Proxy implements Subject {
private RealSubject realSubject;
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
preRequest();
realSubject.request();
postRequest();
}
private void preRequest() {
System.out.println("代理预处理");
}
private void postRequest() {
System.out.println("代理后续处理");
}
}
// 使用示例
Subject proxy = new Proxy();
proxy.request();
2. 动态代理
JDK动态代理实现
import java.lang.reflect.*;
// 动态代理处理器
public class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理预处理");
Object result = method.invoke(target, args);
System.out.println("动态代理后续处理");
return result;
}
}
// 使用示例
RealSubject realSubject = new RealSubject();
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new DynamicProxyHandler(realSubject)
);
proxy.request();
三、代理模式的应用场景
1. 远程代理(RMI示例)
// 远程接口
public interface RemoteService extends Remote {
String getData() throws RemoteException;
}
// 远程服务实现
public class RemoteServiceImpl extends UnicastRemoteObject implements RemoteService {
public RemoteServiceImpl() throws RemoteException {}
public String getData() throws RemoteException {
return "远程数据";
}
}
// 客户端使用远程代理
RemoteService service = (RemoteService) Naming.lookup("rmi://localhost/RemoteService");
String data = service.getData();
2. 虚拟代理(延迟加载)
public class ImageProxy implements Image {
private String filename;
private RealImage realImage;
public ImageProxy(String filename) {
this.filename = filename;
}
public void display() {
if (realImage == null) {
realImage = new RealImage(filename); // 延迟加载
}
realImage.display();
}
}
3. 保护代理(访问控制)
public class ProtectionProxy implements SensitiveOperation {
private RealSensitiveOperation realOperation;
private String userRole;
public ProtectionProxy(String userRole) {
this.userRole = userRole;
}
public void operation() {
if (!"ADMIN".equals(userRole)) {
throw new SecurityException("无权限访问");
}
if (realOperation == null) {
realOperation = new RealSensitiveOperation();
}
realOperation.operation();
}
}
4. 智能引用代理
public class SmartReferenceProxy implements DatabaseConnection {
private RealDatabaseConnection realConnection;
private int referenceCount = 0;
public Connection getConnection() {
if (realConnection == null) {
realConnection = new RealDatabaseConnection();
}
referenceCount++;
return realConnection.getConnection();
}
public void release() {
if (--referenceCount == 0 && realConnection != null) {
realConnection.close();
realConnection = null;
}
}
}
四、代理模式的变体
1. CGLIB动态代理(无需接口)
import net.sf.cglib.proxy.*;
public class CglibProxy implements MethodInterceptor {
public Object getProxy(Class clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CGLIB代理预处理");
Object result = proxy.invokeSuper(obj, args);
System.out.println("CGLIB代理后续处理");
return result;
}
}
// 使用示例
RealSubject proxy = (RealSubject) new CglibProxy().getProxy(RealSubject.class);
proxy.request();
2. Spring AOP代理
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("方法调用前: " + joinPoint.getSignature().getName());
}
}
五、代理模式的优缺点
优点
- 职责清晰:代理对象专注于控制访问
- 扩展性好:不修改目标对象即可增加功能
- 保护目标对象:控制对敏感对象的访问
- 性能优化:实现延迟加载和缓存
缺点
- 复杂度增加:引入额外抽象层
- 性能开销:代理调用可能增加处理时间
- 实现复杂:动态代理需要理解反射机制
六、最佳实践
- 合理选择代理类型:根据场景选择静态或动态代理
- 保持代理简洁:避免在代理中加入过多业务逻辑
- 接口设计:优先基于接口而非具体类实现代理
- 性能考量:对性能敏感场景评估代理开销
- 文档化:明确记录代理的职责和功能
七、总结
代理模式是控制对象访问的强大工具,特别适用于:
- 需要控制对复杂或敏感对象的访问
- 需要为对象添加额外功能而不修改其代码
- 需要实现延迟加载或远程访问
- 需要添加访问日志、监控等功能
在实际开发中,代理模式常见于:
- RPC框架(如Dubbo)
- Spring AOP实现
- ORM框架(如Hibernate延迟加载)
- 安全控制框架
- 缓存实现
正确使用代理模式可以提高系统的安全性和灵活性,但需要注意不要过度使用,以免增加系统复杂性。