什么是代理Bean?
大家好,我是程序员花卷,现在是一名大三学生,在持续学习进步,在这里分享一些我的学习感悟和积累
之前面试的时候,面试官问我SpringBean的生命周期 ,我非常流利的答出来了,然后面试官追问: 代理Bean是生命周期是咋样的?普通bean的生命周期和代理bean他们之间加载的区别是什么?我就直接卡壳了,今天我们来一起学习一下代理Bean,让你面试的时候遇到这个问题也能凯凯而谈。
首先我们先搞懂什么是代理 Bean?
普通 Bean:容器实例化的原始目标对象 (target),就是你写的业务类本身。
代理 Bean:Spring 生成的包装对象,包装了原始目标 Bean。调用代理 Bean 方法时,会先执行 AOP 切面逻辑(前置、后置、异常通知),再去调用原始对象的目标方法。
关键点:放到 Spring 容器中的引用,是代理对象 ,代理内部持有
target(原始普通 bean)。 例如@Transactional事务也是 AOP 代理,拿到的 bean 是代理 bean,不是原始类对象。
在来看看代理 Bean 是如何加载 / 创建的?
时机:Bean 的后置处理,AbstractAutoProxyCreator(核心)
代理不是在实例化阶段创建 ,是在普通 Bean 实例化、属性填充、初始化完成之后,由BeanPostProcessor做替换。 完整流程:
- Spring 执行实例化 → 反射 new 出原始目标普通 Bean 对象 (target 对象),完成依赖注入、
@PostConstruct、InitializingBean 初始化。 AbstractAutoProxyCreator(实现SmartInstantiationAwareBeanPostProcessor)的 postProcessAfterInitialization 触发。- 判断当前 Bean 是否匹配切面表达式(pointcut),需要 AOP 增强:
- 如果匹配 → 使用 JDK / CGLIB 生成代理对象(代理 Bean)。代理对象内部持有 target(原始 bean)。
- 不匹配 → 返回原来普通 Bean,不代理。
- Spring 把代理对象放回单例池 ,后续
getBean()、@Autowired 注入拿到的就是代理 Bean,而不是原始对象。
⚠️重要:原始目标 Bean 依然存在,只是容器对外暴露的引用被替换成代理。
在来看看普通 Bean 和 代理 Bean 加载、生命周期区别
普通 Bean 完整生命周期
- 实例化(反射构造器 new 对象)
- 属性填充 populateBean(@Autowired 注入)
- BeanPostProcessor before 初始化
- 初始化:@PostConstruct → InitializingBean → init‑method
- BeanPostProcessor after 初始化
- 放入单例池,对外提供使用
代理 Bean 的流程
- 实例化:new 原始目标对象(普通对象)
- 属性填充
- before 初始化后置处理器
- 初始化(@PostConstruct、InitializingBean 全部执行在原始 target 对象上)
postProcessAfterInitialization:生成代理对象
✨注意:代理对象没有执行构造器、没有走属性注入、不走初始化方法!初始化全部发生在原始 target 上。
- 将代理对象存入单例池;原始 target 对象被代理持有,不再直接对外暴露。
核心对比区别
| 维度 | 普通 Bean | AOP 代理 Bean |
|---|---|---|
| 实例是谁 | 业务类本身 | JDK 代理类 / CGLIB 子类对象 |
| 构造器调用 | 容器反射调用本类构造器 | 代理对象本身不会执行业务类构造器;构造器只调用在原始 target 对象 |
| 属性注入 | populateBean 给当前对象注入属性 | 属性注入只做给原始 target;代理对象不做属性填充 |
| 初始化方法 (@PostConstruct 等) | 在自身对象执行 | 全部执行原始 target 对象,代理对象不执行初始化回调 |
| 创建时机 | instantiate 阶段直接创建 | 原始 bean 完成初始化后,BeanPostProcessor 后置阶段动态生成 |
| 单例池存放 | 存放自己本身对象 | 存放生成后的代理对象;原始 target 被代理内部引用 |
| 方法调用 | 直接执行业务逻辑 | 先走切面通知逻辑,再委托调用 target 目标方法 |
高频面试坑
@PostConstruct写在被 AOP 代理的类上:执行的是原始 target 对象,不是代理对象。- this 调用本类方法不经过 AOP:因为
this拿到的是原始 target 对象,不是容器中的代理 Bean,切面失效。 - CGLIB 代理是子类,但不会通过子类构造器创建目标业务对象,业务对象是独立 new 出来的 target,代理只是包装。
通过这个希望你对代理bean有了一定的认识,我是程序员花卷,持续学习中,如果你觉得文章有帮助,请帮忙转发给更多的好友,感谢大家的阅读。