# 什么是代理模式?一般用在什么场景?

8 min read
Table of Contents

什么是代理模式?一般用在什么场景?

代理模式面试回答

【核心定义】

代理模式是一种结构型设计模式,通过创建一个代理对象来控制对原始对象的访问,在不改变原始对象代码的前提下,为其提供额外的功能或访问控制。

【关键要点】

  1. 核心结构:包含三个角色 - 抽象主题(接口)、真实主题(具体实现类)、代理类(实现相同接口并持有真实主题的引用)
  2. 访问控制:代理对象作为客户端和真实对象之间的中介,可以控制对真实对象的访问时机和条件
  3. 功能增强:在不修改原始对象的前提下,代理可以在调用前后添加额外的逻辑(如日志、缓存、权限验证等)
  4. 透明性:客户端通常不知道自己在使用代理还是真实对象,因为它们实现了相同的接口

【深度推导/细节】

代理模式的实现方式

静态代理:

// 1. 定义接口
interface Subject {
void request();
}
// 2. 真实主题
class RealSubject implements Subject {
public void request() {
System.out.println("真实请求");
}
}
// 3. 代理类
class Proxy implements Subject {
private RealSubject realSubject;
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
preRequest(); // 前置增强
realSubject.request();
postRequest(); // 后置增强
}
}

动态代理(JDK):

  • 基于接口实现,使用Proxy.newProxyInstance()创建代理对象
  • 通过InvocationHandler接口统一处理所有方法调用
  • 运行时动态生成代理类字节码

CGLIB代理:

  • 基于继承实现,可以代理没有接口的类
  • 通过Enhancer创建子类代理
  • 使用MethodInterceptor拦截方法调用

性能与选择考量

  • 静态代理:编译时确定,性能好但灵活性差,每个代理类只能代理一个接口
  • JDK动态代理:需要接口,生成速度快,调用性能略低于静态代理
  • CGLIB代理:无需接口,生成速度慢但调用性能好,final类/方法无法代理

【关联/对比】

代理模式 vs 装饰器模式

维度代理模式装饰器模式
目的控制访问,增强非业务功能增强对象功能,添加职责
关注点访问控制、延迟加载、远程访问功能扩展、组合替代继承
关系代理和真实对象关系固定装饰器和组件可以动态组合
创建时机通常在编译时确定运行时动态组合

与其他模式的关联

  • 适配器模式:改变接口,代理模式保持接口一致
  • 门面模式:简化复杂系统接口,代理模式控制单个对象访问
  • 责任链模式:多个对象处理请求,代理模式只有一个代理对象

【典型应用场景】

1. 远程代理(Remote Proxy)

  • 场景:分布式系统中,客户端调用远程服务
  • 实现:代理对象处理网络通信细节,客户端像调用本地对象一样使用
  • 示例:RPC框架、EJB、Spring Remoting

2. 虚拟代理(Virtual Proxy)

  • 场景:创建开销大的对象需要延迟初始化
  • 实现:代理先创建轻量级对象,真正需要时才创建真实对象
  • 示例:大图片加载、复杂计算延迟执行

3. 保护代理(Protection Proxy)

  • 场景:基于权限控制对对象的访问
  • 实现:代理检查调用者权限,决定是否转发请求
  • 示例:Spring Security的方法级安全、操作系统权限控制

4. 智能引用代理(Smart Reference)

  • 场景:为对象访问添加额外管理功能
  • 实现:在访问前后添加计数、缓存、日志等
  • 示例:
    • 引用计数:跟踪对象被引用次数
    • 缓存代理:第一次访问后缓存结果
    • 同步代理:多线程环境下的安全访问
    • 日志代理:记录方法调用信息

5. Spring框架中的代理应用

  • AOP实现:使用JDK动态代理(接口)或CGLIB(类)实现切面编程
  • 事务管理:@Transactional注解通过代理实现事务控制
  • 安全控制:Spring Security使用代理进行权限验证
  • 延迟加载:Hibernate和Spring Data的懒加载机制

6. 实际开发中的具体场景

  • 权限验证:Web应用中的接口访问控制
  • 日志记录:记录方法调用参数、执行时间、结果
  • 性能监控:统计方法执行时间,监控系统性能
  • 缓存加速:对耗时操作结果进行缓存
  • 断路器模式:在微服务调用中添加熔断保护
  • Mock测试:单元测试中模拟外部依赖

『面试官追问』

可能的问题:

  1. JDK动态代理和CGLIB代理有什么区别?如何选择?

    • JDK基于接口,CGLIB基于继承
    • 性能对比:JDK生成快调用慢,CGLIB生成慢调用快
    • Spring AOP默认策略:有接口用JDK,无接口用CGLIB
  2. 代理模式有什么缺点?

    • 增加系统复杂度
    • 可能带来性能损失(特别是动态代理)
    • 调试困难(调用栈变深)
  3. 静态代理和动态代理各适合什么场景?

    • 静态代理:代理关系固定、性能要求高、需要编译时检查
    • 动态代理:代理关系多变、需要减少重复代码、框架开发
  4. Spring AOP是如何实现代理的?

    • 根据目标对象是否有接口选择代理方式
    • 通过ProxyFactoryBean或@AspectJ注解配置
    • 使用DefaultAopProxyFactory决定创建哪种代理
  5. 代理模式会导致哪些设计问题?

    • 可能违反单一职责原则(代理类承担额外职责)
    • 可能隐藏真实对象的复杂性
    • 过度使用会导致系统难以理解和维护

回答技巧:

  • 结合具体框架(Spring、MyBatis等)举例说明
  • 提到实际项目中的应用经验
  • 对比不同实现方式的优缺点
  • 说明在微服务、分布式系统中的特殊应用

代理模式是实际开发中应用最广泛的设计模式之一,深入理解其原理和应用场景,能够帮助设计出更加灵活、可维护的系统架构。

My avatar

文章看完了,不打算去别的篇章转转吗?👀 感谢你的耐心阅读!如果你有问题想探讨,或者发现了文中的 Bug,请务必通过页脚的链接联系我


More Posts

Comments