一、代理模式的核心概念
1. 定义
为目标对象提供 "代理类",让调用方不直接访问目标对象,而是通过代理类间接访问,从而在代理类中实现功能增强(比如日志、权限校验)。
2. 核心角色(以 "房屋租赁" 为例)
| 角色 | 对应示例 | 作用说明 |
|---|---|---|
| Subject | HouseSubject接口 |
定义目标对象和代理类的共同行为(比如 "租房") |
| RealSubject | RealHouseSubject(房东) |
目标对象(被代理的实际业务执行者) |
| Proxy | HouseProxy(中介) |
代理类,包装目标对象,在调用目标方法前后添加增强逻辑 |
静态代理的实现步骤(以房屋租赁为例)
1. 定义共同接口(Subject)

2. 实现目标对象(RealSubject)

3. 实现代理类(Proxy)

4. 使用代理


静态代理的核心特点
- 提前创建 :代理类的
.class文件在程序运行前就已存在(比如HouseProxy是提前写好的); - 功能增强:不修改目标对象代码,通过代理类实现 "附加逻辑"(符合 "开闭原则");
- 局限性 :一个代理类只能代理一种类型的目标对象,若要代理多个类,需写多个代理类(所以 Spring AOP 实际用的是动态代理,解决这个局限性)。
和 Spring AOP 的关系
静态代理是代理模式的基础,而 Spring AOP 的底层是动态代理(运行时自动生成代理类),但核心思想一致:通过代理类包装目标对象,实现无侵入的功能增强。
二、动态代理的核心优势
相比静态代理,动态代理无需为每个目标对象写单独的代理类 ,而是在程序运行时动态生成代理对象,更灵活、更通用。
2.1JDK 动态代理的实现步骤(以房屋租赁为例)
步骤 1:准备 "干活的对象"(目标对象)
- 目标:确定 "要被代理的实体 + 要干的活";
- 人话:找个 "房东"(RealHouseSubject),他会干 "租房"(rentHouse 方法)这个活;
- 代码对应:

步骤 2:写 "中介的规则"(InvocationHandler)
- 目标:定义 "中介要在房东干活前后加什么额外操作";
- 人话:中介(JDKInvocationHandler)要在房东租房前说 "开始代理",租房后说 "代理结束";
- 代码对应:

步骤 3:生成 "中介"(动态代理对象)
- 目标:让 JVM 自动创建 "中介",代替房东和用户打交道;
- 人话:告诉 JVM"用房东的类加载器、房东会的活(接口)、中介的规则",生成一个中介;
- 代码对应:

步骤 4:看结果(验证逻辑)
运行后输出:

3.JDK 动态代理的关键 API
| API | 作用说明 |
|---|---|
InvocationHandler |
方法调用处理器接口,invoke方法是代理增强逻辑的入口(参数含代理对象、目标方法、方法参数)。 |
Proxy.newProxyInstance |
动态生成代理对象的核心方法,需传入类加载器、目标对象实现的接口、InvocationHandler 实例。 |
4.JDK 动态代理的局限性
只能代理实现了接口的类 (因为newProxyInstance需要传入接口数组)。若要代理无接口的类,需用CGLIB 动态代理(后续内容)。
5.和 Spring AOP 的关系
Spring AOP 默认优先用JDK 动态代理 (代理有接口的类),若目标类无接口,则自动切换为CGLIB 动态代理,底层逻辑与上述一致 ------ 通过动态生成代理类实现无侵入的功能增强。
三、AOP + 代理模式核心拆解
第一层:先搞懂"目标对象"
核心逻辑
目标对象 = Spring 管理的 Bean(比如 Controller/Service) + 这个 Bean 里的业务方法(比如接口方法 / 保存用户方法)
解释
就是 "真正干活的对象 + 具体要干的活",比如:
- 干活的对象:
UserController实例(Spring 自动创建的 Bean); - 具体的活:
getUserById(Long id)方法(查询用户的业务逻辑)。
第二层:为什么需要"代理"(AOP 的本质)
核心逻辑
不想修改目标对象的代码,但想给 "具体的活" 加额外逻辑(日志 / 权限 / 事务)→ 找个 "中间人"(代理对象)帮我们加。
解释
比如:房东(目标对象)只想 "租房"(核心活),不想管 "带看房 / 签合同"(额外活)→ 找中介(代理对象),中介帮房东加这些额外活,房东只干核心的租房。
第三层:「静态代理」vs「动态代理」(代理的两种方式)
| 类型 | 核心逻辑 | 人话解释 |
|---|---|---|
| 静态代理 | 提前写死代理类(一个目标对象对应一个代理类) | 给房东 A 写个专属中介,给房东 B 写另一个专属中介 |
| 动态代理 | 运行时自动生成代理类(所有目标对象共用一套逻辑) | 一个中介公司,能代理所有房东,不用单独写中介 |
关键:Spring AOP 用的是"动态代理"
- JDK 动态代理:代理有接口的类(比如 Controller/Service 都实现了接口);
- CGLIB 动态代理:代理没接口的类(兜底方案)。
第四层:Spring AOP 的核心组件(代理的 "包装")
把动态代理的逻辑封装成 3 个好懂的组件,不用自己写代理类:
1. 切面类(@Aspect + @Component)
- 核心逻辑:告诉 Spring "这是一个 AOP 增强类",并交给 Spring 管理;
- 人话:就是 "中介公司的规则手册",定义了 "要帮哪些房东干活 + 要加哪些额外活"。
2. 切点(execution/@annotation)
- 核心逻辑:划定 "要增强哪些目标对象的方法"(哪些房东要被代理);
- 人话:规则 1:"只代理朝阳区的房东"(execution 匹配包 / 类);规则 2:"只代理贴了"急租"标签的房东"(@annotation 匹配注解)。
3. 通知(@Before/@Around 等)
- 核心逻辑:定义 "要加的额外活"(什么时候加、加什么);
- 人话:规则:"带客户看房(@Before)→ 房东租房 → 收中介费(@After)"。
第五层:完整执行流程
以 "访问 UserController 的 getUserById 方法" 为例:
- 你调用
userController.getUserById(1)→ 实际调用的是 Spring 生成的"代理对象"; - 代理对象先执行通知逻辑(比如 @Before 打印日志);
- 代理对象调用"目标对象"的
getUserById(1)(真正的查询逻辑); - 代理对象再执行后续通知(比如 @After 统计耗时);
- 返回结果给你。
核心总结(一句话)
Spring AOP = 动态代理(自动生成中介) + 切面(中介规则) + 切点(选房东) + 通知(加额外活),最终实现 "不修改目标对象代码,却能增强其方法"。
四、CGLIB 动态代理
1.先搞懂:CGLIB 是干嘛的?
JDK 动态代理只能代理 "有接口的类",而CGLIB 是用来代理 "没有接口的类" (比如普通的 Java 类),它的原理是动态生成目标类的子类,通过子类来实现增强。
2.CGLIB 动态代理的 3 步核心动作
步骤 1:准备 "要被代理的类"(不用接口!)
- 目标:找一个 "没实现接口的类"(比如普通的房东类);
- 人话 :房东类
RealHouseSubject没实现任何接口,但会干 "租房" 这个活; - 代码对应:

步骤 2:写 "增强规则"(MethodInterceptor)
- 目标:定义 "代理要在房东干活前后加什么操作";
- 人话:中介(CGLIBInterceptor)要在房东租房前说 "开始代理",租房后说 "代理结束";
- 代码对应:

步骤 3:生成 "代理子类"(Enhancer.create)
- 目标:让 CGLIB 动态生成目标类的子类(代理类);
- 人话:告诉 CGLIB"要代理的类 + 增强规则",生成一个 "房东的子类(中介)";
- 代码对应:

步骤 4:看结果(和 JDK 代理一样)
运行后输出:

3.CGLIB 和 JDK 代理的核心对比
| 维度 | JDK 动态代理 | CGLIB 动态代理 |
|---|---|---|
| 代理条件 | 必须实现接口 | 可以代理无接口的类(生成子类) |
| 核心 API | InvocationHandler + Proxy | MethodInterceptor + Enhancer |
| 底层原理 | 基于接口的动态代理 | 基于子类的动态代理 |
| Spring AOP 场景 | 优先用(代理有接口的 Bean) | 兜底用(代理无接口的 Bean) |
4.总结 CGLIB
CGLIB 是 JDK 代理的 "补位方案"------ 专门解决 "无接口类的代理问题",通过生成目标类的子类,实现和 JDK 代理一样的增强效果,Spring AOP 会自动在 JDK 和 CGLIB 之间切换。
五、Spring AOP 的源码
1.Spring AOP 的核心逻辑:谁来生成代理?
Spring AOP 生成代理的核心类是AnnotationAwareAspectJAutoProxyCreator,它的父类AbstractAutoProxyCreator里的createProxy方法,是生成代理的 "入口"。
2.生成代理的 3 步核心流程(源码逻辑)
步骤 1:创建 "代理工厂"(ProxyFactory)
- 目标:封装代理的配置信息(比如用 JDK 还是 CGLIB);
- 代码对应:

步骤 2:决定 "用 JDK 还是 CGLIB"(核心判断)
通过proxyTargetClass这个配置项,决定代理方式:
| proxyTargetClass 值 | 目标对象情况 | 代理方式 |
|---|---|---|
| false(默认) | 实现了接口 | JDK 代理 |
| false(默认) | 没实现接口 | CGLIB 代理 |
| true | 不管有没有接口 | CGLIB 代理 |

步骤 3:生成代理对象(调用 JDK/CGLIB 的 API)
代理工厂通过getProxy方法,最终调用我们之前学的 JDK/CGLIB API 生成代理:
- JDK 代理 :调用
Proxy.newProxyInstance(对应JdkDynamicAopProxy类);

- CGLIB 代理 :调用
Enhancer.create(对应CglibAopProxy类);

3.Spring Boot 中的关键配置
- Spring Boot 2.x 开始,默认用 CGLIB 代理 (相当于默认
proxyTargetClass=true); - 若要改回 JDK 代理,需在配置文件加:

4.一句话总结 Spring AOP 源码逻辑
Spring AOP 通过ProxyFactory封装配置,根据proxyTargetClass和 "目标类是否有接口",自动选择 JDK/CGLIB 代理,最终调用对应的动态代理 API 生成代理对象 ------我们之前学的 JDK/CGLIB,就是 Spring AOP 的底层实现。