Java面试必备:代理模式详解:概念、应用场景与实例分析
Java面试题 - 什么是代理模式?一般用在什么场景?
回答重点
代理模式(ProxyPattern)是一种结构型设计模式,在不改变原始对象的前提下,通过引入一个代理对象来控制对原始对象的访问,实现额外的功能。例如控制权限、延迟加载、缓存等。
这个模式在我们业务中太常见了,例如动态代理就是代理模式,SpringAOP就是动态代理,RPC框架也是使用了动态代理才使得调用远程方法和本地方法一样。
所以,统一报错、监控、限流、鉴权等等,需要跟业务解耦的功能,我们基本上都是使用代理类进行统一处理的。
代理模式的特点:
- 间接访问:客户端通过代理访问实际对象,代理对象负责对实际对象的控制。
- 功能增强:代理对象可以在访问实际对象之前或之后添加额外的功能。
- 解耦性:客户端不直接与实际对象交互,通过代理对象可以透明地扩展实际对象的功能。
一般用在什么场景?
- 访问控制:对实际对象的访问需要进行权限验证时。
- 性能优化:通过代理实现缓存或延迟加载以提高系统性能。
- 远程访问(rpc调用):客户端需要访问远程对象时,通过代理封装远程调用的细节。
- 日志记录:在方法调用时添加日志记录功能。
典型场景:
- 远程代理:为远程对象提供本地代表。
- 权限代理:控制对对象的访问权限。
- 智能引用:在访问对象时增加一些附加行为,如引用计数、日志记录等。
什么是代理模式?
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,可以在不改变原始类(或目标类)代码的情况下,通过引入代理类来给原始类提供附加功能。
上面的类图展示了代理模式的基本结构:
- Subject:定义了RealSubject和Proxy的公共接口
- RealSubject:真实的对象,执行实际的业务逻辑
- Proxy:代理对象,持有对RealSubject的引用,可以控制对RealSubject的访问
代理模式的应用场景
代理模式在软件开发中有广泛的应用,以下是几种常见的应用场景:
1. 远程代理(Remote Proxy)
为位于不同地址空间的对象提供一个本地代表。例如RPC框架中的存根(Stub)就是远程代理。
2. 虚拟代理(Virtual Proxy)
用于延迟加载大对象。例如在图片加载时,先显示缩略图或占位图,等真正需要时再加载大图。
// 虚拟代理示例代码
public class ImageProxy implements Image {
private HighResolutionImage realImage;
public void showImage() {
if (realImage == null) {
realImage = new HighResolutionImage(); // 真正需要时才加载
}
realImage.showImage();
}
}
3. 保护代理(Protection Proxy)
控制对原始对象的访问权限。例如根据不同用户权限决定是否可以访问某些资源。
4. 智能引用代理(Smart Reference Proxy)
在访问对象时执行附加操作,如:
- 引用计数
- 对象是否被锁定检查
- 首次引用时持久化对象
5. 缓存代理(Cache Proxy)
为开销大的运算结果提供临时存储,下次请求相同数据时直接返回缓存结果。
代理模式的实现方式
代理模式主要有两种实现方式:
1. 静态代理
在编译时就已经确定代理关系,代理类和被代理类在编译时就确定了。
// 静态代理示例
public interface Subject {
void request();
}
public class RealSubject implements Subject {
public void request() {
System.out.println("RealSubject处理请求");
}
}
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("代理后续处理");
}
}
2. 动态代理
在运行时动态创建代理类,Java中常用的有JDK动态代理和CGLIB动态代理。
// JDK动态代理示例
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;
}
public static Object createProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new DynamicProxyHandler(target)
);
}
}
代理模式的优缺点
优点:
- 职责清晰:真实角色只需关注业务逻辑,其他事务由代理完成
- 高扩展性:可以在不修改目标对象的前提下扩展功能
- 智能化:动态代理可以实现更灵活的代理逻辑
缺点:
- 增加系统复杂度:引入了额外的代理层
- 性能开销:代理调用会带来一定的性能损耗,特别是远程代理
- 实现复杂度:动态代理的实现相对复杂
实际应用案例
Spring AOP中的代理模式
Spring AOP使用JDK动态代理(针对接口)或CGLIB(针对类)来实现面向切面编程。
MyBatis中的代理模式
MyBatis的Mapper接口通过动态代理实现,开发者只需定义接口,MyBatis会在运行时生成实现类。
// MyBatis Mapper接口示例
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
User getUserById(int id);
}
// 实际使用时
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1); // 动态代理实现
总结
代理模式是一种非常有用的设计模式,它通过引入代理对象来控制对原始对象的访问。代理模式的主要应用场景包括远程调用、延迟加载、访问控制、智能引用和缓存等。根据实现方式的不同,代理模式可以分为静态代理和动态代理两种形式。
在实际开发中,代理模式被广泛应用于各种框架和库中,如Spring的AOP、MyBatis的Mapper接口、RPC框架等。合理使用代理模式可以有效地解耦业务逻辑与非功能性需求,提高代码的可维护性和扩展性。
理解代理模式的关键在于认识到它"控制访问"的本质,而不是"增强功能"(这是装饰器模式的特点)。当需要在访问对象时添加一些控制逻辑,而又不希望这些逻辑侵入原始对象时,代理模式是一个很好的选择。
更多推荐



所有评论(0)