👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中… 博客更新速度++
👍 欢迎点赞、收藏、关注,跟上我的更新节奏
🎵 当你的天空突然下了大雨,那是我在为你炸乌云
文章目录
- 一、入门
 
- 什么是代理模式?
 - 为什么要代理模式?
 - 如何实现代理模式?
 
- 静态代理
 - JDK代理
 - CGLIB动态代理
 - 三种代理模式对比
 - 二、代理模式在框架源码中的运用
 
- Spring Framework 中的 AOP 代理
 - MyBatis 中的 Mapper 接口代理
 - 三、总结
 
- 代理模式的优点
 - 代理模式的缺点
 - 代理模式的适用场景
 
一、入门
什么是代理模式?
代理模式(Proxy Pattern)是一种结构型设计模式,允许你提供一个代理对象来控制对另一个对象的访问。
 代理对象在客户端和目标对象之间起到中介作用,可以在不改变目标对象的情况下增加额外的功能或控制访问。
为什么要代理模式?
- 违反单一职责原则: 
- 原始对象的核心职责是实现业务逻辑,但如果将额外的功能(如权限检查、日志记录等)直接写入原始对象,会导致对象的职责变得复杂,难以维护。
 - 例如,一个
UserService类如果既要处理用户登录逻辑,又要记录日志、检查权限,代码会变得臃肿。 
 - 代码重复: 
- 如果多个地方需要对对象的访问进行相同的控制(如权限检查),开发者可能会在每个调用点重复编写相同的代码,导致代码冗余。
 
 - 难以扩展: 
- 如果需要在访问对象时增加新的功能(如缓存、延迟加载等),可能需要直接修改原始对象的代码,这会破坏开闭原则(对扩展开放,对修改关闭)。
 
 - 性能问题: 
- 某些场景下,对象的创建或初始化成本较高(如加载大文件、连接远程服务等)。如果没有代理模式,可能会在不需要时提前创建对象,导致资源浪费。
 
 - 安全性问题: 
- 如果没有代理模式,客户端可以直接访问敏感对象,可能会绕过必要的安全检查或权限控制。
 
 
如何实现代理模式?
- Subject(抽象主题):定义真实对象和代理对象的共同接口,客户端通过该接口与真实对象交互。
 - RealSubject(真实主题):实现Subject接口,是代理对象所代表的真实对象。
 - Proxy(代理):实现
Subject接口,持有对RealSubject的引用,控制对RealSubject的访问,并可以在访问前后添加额外操作。 
【案例】订单加强
 网购订单处理:假设我们需要在用户下单时记录日志,但不想修改核心的订单处理逻辑。
静态代理
Subject(抽象主题): OrderService接口,定义订单下达。
public interface OrderService {void createOrder(String product);
}
 
RealSubject(真实主题):OrderServiceImpl类,实现下单逻辑。
public class OrderServiceImpl implements OrderService {@Overridepublic void createOrder(String product) {System.out.println("订单创建成功,商品:" + product);}
}
 
Proxy(代理):OrderServiceStaticProxy(手动编写代理类,添加日志记录)
public class OrderServiceStaticProxy implements OrderService {private OrderService orderService;public OrderServiceStaticProxy(OrderService orderService) {this.orderService = orderService;}@Overridepublic void createOrder(String product) {System.out.println("[静态代理] 记录日志:开始下单");orderService.createOrder(product);System.out.println("[静态代理] 记录日志:下单完成");}
}
 
测试类
public class Client {public static void main(String[] args) {OrderService realService = new OrderServiceImpl();OrderService proxy = new OrderServiceStaticProxy(realService);proxy.createOrder("iPhone 15");}
}
 
输出
[静态代理] 记录日志:开始下单
订单创建成功,商品:iPhone 15
[静态代理] 记录日志:下单完成
 
JDK代理
通过JDK的InvocationHandler和Proxy类动态生成代理对象。
 Subject(抽象主题): OrderService接口,定义订单下达。
public interface OrderService {void createOrder(String product);
}
 
RealSubject(真实主题):OrderServiceImpl类,实现下单逻辑。
public class OrderServiceImpl implements OrderService {@Overridepublic void createOrder(String product) {System.out.println("订单创建成功,商品:" + product);}
}
 
Proxy(代理):InvocationHandler类,InvocationHandler接口。
public class LogInvocationHandler implements InvocationHandler {private Object target; // 真实对象public LogInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("[JDK动态代理] 记录日志:开始执行方法 " + method.getName());Object result = method.invoke(target, args);System.out.println("[JDK动态代理] 记录日志:方法执行完成");return result;}
}
 
客户端调用
public class Client {public static void main(String[] args) {OrderService realService = new OrderServiceImpl();OrderService proxy = (OrderService) Proxy.newProxyInstance(realService.getClass().getClassLoader(),realService.getClass().getInterfaces(),new LogInvocationHandler(realService));proxy.createOrder("MacBook Pro");}
}
 
输出结果
[JDK动态代理] 记录日志:开始执行方法 createOrder
订单创建成功,商品:MacBook Pro
[JDK动态代理] 记录日志:方法执行完成
 
CGLIB动态代理
通过继承目标类生成子类来实现代理(无需接口)
 RealSubject(真实主题):OrderServiceImpl类,实现下单逻辑。(这个增强无需接口)
// 真实对象(无需接口)
public class OrderService {public void createOrder(String product) {System.out.println("订单创建成功,商品:" + product);}
}
 
Proxy(代理):MethodInterceptor类
public class LogMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("[CGLIB代理] 记录日志:开始执行方法 " + method.getName());Object result = proxy.invokeSuper(obj, args);System.out.println("[CGLIB代理] 记录日志:方法执行完成");return result;}
}
 
客户端
public class Client {public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(OrderService.class); // 设置父类enhancer.setCallback(new LogMethodInterceptor()); // 设置回调OrderService proxy = (OrderService) enhancer.create(); // 创建代理对象proxy.createOrder("AirPods Pro");}
}
 
输出结果
[CGLIB代理] 记录日志:开始执行方法 createOrder
订单创建成功,商品:AirPods Pro
[CGLIB代理] 记录日志:方法执行完成
 
三种代理模式对比
| 代理类型 | 特点 | 适用场景 | 
|---|---|---|
| 静态代理 | 手动编写代理类,直接调用目标对象。 | 代理逻辑简单,目标对象固定。 | 
| JDK动态代理 | 基于接口动态生成代理类,通过反射调用目标方法。 | 需要代理接口的实现类。 | 
| CGLIB代理 | 通过继承目标类生成子类代理,无需接口。性能较高,但生成代理类较慢。 | 需要代理没有实现接口的类。 | 
适用场景
- 静态代理:适合代理逻辑简单且目标对象固定的场景。
 - JDK动态代理:适合基于接口的代理(如Spring AOP默认使用JDK代理)。
 - CGLIB代理:适合代理没有接口的类(如Spring AOP在类没有接口时自动切换为CGLIB)。
 
二、代理模式在框架源码中的运用
Spring Framework 中的 AOP 代理
Spring AOP 通过代理模式实现方法拦截(如事务管理、日志记录),核心类是 ProxyFactoryBean 和动态代理生成器。
核心角色与类:
- Subject(抽象主题):被代理的接口或类(如 UserService 接口)。
 - RealSubject(真实主题):实际的目标对象(如 UserServiceImpl 类)。
 - Proxy(代理):由 Spring 动态生成的代理对象,具体分为两类:
 - JDK 动态代理:通过 JdkDynamicAopProxy 类生成(代理接口)。
 - CGLIB 代理:通过 ObjenesisCglibAopProxy 类生成(代理类,无接口时使用)。
 
// Spring AOP 生成代理的核心逻辑(ProxyFactoryBean)
public class ProxyFactoryBean {private Object target;          // RealSubject(真实对象)private Class<?>[] interfaces;  // Subject(接口)private Advice advice;          // 增强逻辑(如事务、日志)public Object getObject() {// 根据配置选择生成 JDK 或 CGLIB 代理return createAopProxy().getProxy();}
}
 
执行流程:
- 客户端调用代理对象的方法(如
userService.save())。 - 代理对象拦截方法调用,执行增强逻辑(如开启事务)。
 - 代理对象通过反射调用真实对象的方法(UserServiceImpl.save())。
 - 返回结果前,执行后置增强逻辑(如提交事务)。
 
MyBatis 中的 Mapper 接口代理
MyBatis 通过代理模式将 Mapper 接口的方法调用转换为 SQL 执行,核心类是 MapperProxy。
核心角色与类
- Subject(抽象主题):
Mapper接口(如UserMapper)。 - RealSubject(真实主题):不存在真实实现类,由代理直接处理逻辑。
 - Proxy(代理):
MapperProxy类,实现InvocationHandler接口,动态代理Mapper接口。 
// MyBatis 的 Mapper 代理生成逻辑(MapperProxyFactory)
public class MapperProxyFactory<T> {private final Class<T> mapperInterface;public T newInstance(SqlSession sqlSession) {final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface);return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);}
}// MapperProxy 实现 InvocationHandler
public class MapperProxy<T> implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 将方法调用转换为 SQL 执行(如执行 select * from user where id = ?)return execute(method, args);}
}
 
执行流程
- 客户端调用 
UserMapper.findById(1)。 MapperProxy拦截方法调用,解析方法名和参数。- 根据方法名找到对应的 SQL 语句并执行。
 - 返回数据库查询结果。
 
三、总结
代理模式的优点
- 职责清晰: 
- 代理对象负责处理与核心业务无关的逻辑(如权限检查、日志记录、延迟加载等),而真实对象只需关注核心业务逻辑。
 - 符合单一职责原则。
 
 - 增强功能: 
- 在不修改真实对象的情况下,通过代理对象增强功能(如事务管理、缓存、延迟加载等)。
 
 - 解耦: 
- 代理模式将客户端与真实对象解耦,客户端只需与代理对象交互,无需直接访问真实对象。
 
 - 安全性: 
- 代理对象可以控制对真实对象的访问,增加权限检查等安全措施。
 
 - 灵活性: 
- 动态代理(如 JDK 动态代理、CGLIB 代理)可以在运行时动态生成代理对象,适应不同的需求。
 
 
代理模式的缺点
- 复杂性增加: 
- 引入代理对象会增加系统的复杂性,尤其是动态代理的实现需要理解反射和字节码生成技术。
 
 - 性能开销: 
- 代理模式可能会引入额外的性能开销,尤其是在频繁调用时(如动态代理的反射调用)。
 
 - 代码冗余: 
- 静态代理需要为每个真实对象编写代理类,可能导致代码冗余。
 
 - 调试困难: 
- 动态代理生成的代理类在运行时才存在,调试时可能不如静态代理直观。
 
 
代理模式的适用场景
- 远程代理: 
- 为位于不同地址空间的对象提供本地代表(如 RPC 框架中的远程服务调用)。
 
 - 虚拟代理: 
- 延迟创建开销较大的对象,直到真正需要时才创建(如图片懒加载、大文件加载)。
 
 - 保护代理: 
- 控制对敏感对象的访问,基于权限决定是否允许访问(如权限校验)。
 
 - 智能引用代理: 
- 在访问对象时执行额外操作(如引用计数、懒加载、缓存等)。
 
 - AOP(面向切面编程): 
- 在方法调用前后增加通用逻辑(如日志记录、事务管理、性能监控等)。
 
 - 延迟初始化: 
- 在需要时才初始化对象,节省资源(如 
Hibernate的延迟加载)。 
 - 在需要时才初始化对象,节省资源(如 
 - 简化客户端调用: 
- 客户端只需与代理对象交互,无需关心真实对象的复杂性(如 MyBatis 的 
Mapper代理)。 
 - 客户端只需与代理对象交互,无需关心真实对象的复杂性(如 MyBatis 的