Spring Bean生命周期
目录
一、Bean 完整生命周期
实例化 → 属性注入 → Aware回调 → BeanPostProcessor前置 → 初始化 → BeanPostProcessor后置 → 使用 → 销毁
详细流程
- 实例化(Instantiation)
- Constructor →
new XxxBean()
- 属性注入(Population)
@Autowired / @Value / setter 注入
- Aware 回调
BeanNameAware.setBeanName()BeanFactoryAware.setBeanFactory()ApplicationContextAware.setApplicationContext()
- BeanPostProcessor.postProcessBeforeInitialization() ← 前置处理
- 初始化(Initialization)
@PostConstructInitializingBean.afterPropertiesSet()init-method(自定义初始化方法)
- BeanPostProcessor.postProcessAfterInitialization() ← 后置处理
- Bean 就绪,可使用
- 销毁(Destruction)
@PreDestroyDisposableBean.destroy()destroy-method(自定义销毁方法)
代码验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| @Component public class LifecycleBean implements BeanNameAware, InitializingBean, DisposableBean {
public LifecycleBean() { System.out.println("1. Constructor"); }
@Autowired public void setDependency(Dependency dep) { System.out.println("2. 属性注入"); }
@Override public void setBeanName(String name) { System.out.println("3. BeanNameAware: " + name); }
@PostConstruct public void postConstruct() { System.out.println("4. @PostConstruct"); }
@Override public void afterPropertiesSet() { System.out.println("5. InitializingBean.afterPropertiesSet()"); }
@PreDestroy public void preDestroy() { System.out.println("8. @PreDestroy"); }
@Override public void destroy() { System.out.println("8. DisposableBean.destroy()"); } }
|
二、BeanPostProcessor 详解
接口定义
1 2 3 4 5 6 7 8 9 10
| public interface BeanPostProcessor { default Object postProcessBeforeInitialization(Object bean, String beanName) { return bean; } default Object postProcessAfterInitialization(Object bean, String beanName) { return bean; } }
|
核心:对容器中所有 Bean 生效,是 Spring 扩展的灵魂。
执行时机
1 2 3
| ... → 属性注入 → Aware → BeforeInitialization → @PostConstruct → afterPropertiesSet → AfterInitialization → ... ↑ ↑ 前置处理(少用) 后置处理(常用)
|
为什么前置处理少用?
BeforeInitialization 执行时,Bean 的状态:
- ✅ 属性已注入(@Autowired 完成)
- ✅ Aware 回调已完成
- ❌ @PostConstruct 未执行
- ❌ afterPropertiesSet() 未执行
- ❌ init-method 未执行
→ Bean 还没完成初始化,不是一个”完整可用”的对象
原因1:增强一个半成品没有意义
AOP 代理是 BeanPostProcessor 最大的用途。代理要包装的是”完整的 Bean”——初始化逻辑已经执行完毕,所有依赖和状态都已就绪的对象。如果在前置处理创建代理:
- @PostConstruct 里的逻辑还没跑
- 代理对象包裹了一个”没初始化完”的真实对象
- 调用时可能拿到未初始化的状态 → 空指针、数据错乱
原因2:前置处理能做的事,@PostConstruct 都能做
前置处理的需求:在 Bean 初始化前做一些校验、设置。但这些事情完全可以写在 @PostConstruct 里:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public Object postProcessBeforeInitialization(Object bean, String beanName) { if (bean instanceof UserService) { ((UserService) bean).validate(); } return bean; }
@PostConstruct public void init() { validate(); }
|
→ @PostConstruct 是 Bean 自己的逻辑,内聚性更好
→ BeforeInitialization 是框架级介入,通用场景才需要
原因3:Spring 自己的 BeforeInitialization 用法就很窄
Spring 内部使用 BeforeInitialization 的地方极少,主要是:
CommonAnnotationBeanPostProcessor- 处理 @PostConstruct、@PreDestroy 注解
- 这不是”增强 Bean”,而是”驱动初始化流程本身”
ApplicationContextAwareProcessor- 注入 ApplicationContext 等 Aware 回调
- 也是框架内部机制,不是业务增强
→ Spring 自己都只用来做框架内部的事,业务层几乎没有使用场景
原因4:后置处理才是”增强”的正确时机
AfterInitialization 执行时,Bean 的状态:
- ✅ 属性已注入
- ✅ @PostConstruct 已执行
- ✅ afterPropertiesSet() 已执行
- ✅ init-method 已执行
- ✅ Bean 完全就绪
→ 此时创建代理,包裹的是完整对象
→ 代理调用真实对象时,拿到的状态一定是正确的
→ AOP、监控、脱敏、校验… 所有增强都在这时候做
总结对比
| BeforeInitialization | AfterInitialization |
|---|
| Bean 状态 | 半成品(未初始化) | 成品(完全就绪) |
| 能否代理增强 | ❌ 包裹半成品,有风险 | ✅ 包裹完整对象 |
| 业务需求 | 可用 @PostConstruct 替代 | 不可替代 |
| Spring 内部用法 | 驱动初始化流程 | 创建代理、增强功能 |
| 使用频率 | 极少 | 大量(AOP、@Async 等) |
一句话:前置处理时 Bean 还没初始化完,增强半成品没意义;能做的事 @PostConstruct 都能做;真正需要增强的时机是初始化完成后,所以后置处理才是主流。
三、BeanPostProcessor 实战场景
场景1:AOP 代理创建(最经典)
Spring AOP 的核心实现是 AbstractAutoProxyCreator,它实现了 BeanPostProcessor,在 postProcessAfterInitialization 中为 Bean 创建代理。
1 2 3 4 5 6 7 8 9 10 11
| @Component public class MyAutoProxyCreator implements BeanPostProcessor {
@Override public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean.getClass().isAnnotationPresent(MyAspect.class)) { return createProxy(bean); } return bean; } }
|
这就是为什么 @Transactional、@Async 等注解能生效——底层都是 BeanPostProcessor 在初始化后把原始 Bean 替换成了代理对象。
场景2:自定义注解校验
扫描 Bean 上的自定义注解,做校验或增强。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Component public class ApiCheckProcessor implements BeanPostProcessor {
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) { for (Field field : bean.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(RequiredConfig.class)) { field.setAccessible(true); try { Object value = field.get(bean); if (value == null) { throw new IllegalStateException( beanName + "." + field.getName() + " 未配置必填项"); } } catch (IllegalAccessException e) { throw new RuntimeException(e); } } } return bean; } }
|
场景3:接口实现自动替换
根据条件替换 Bean 实现,如动态数据源切换。
1 2 3 4 5 6 7 8 9 10 11
| @Component public class DataSourceProxyProcessor implements BeanPostProcessor {
@Override public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean instanceof DataSource && !"masterDataSource".equals(beanName)) { return new DynamicDataSourceProxy((DataSource) bean); } return bean; } }
|
场景4:监控/日志埋点
为所有 Service 层 Bean 自动添加耗时监控。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Component public class ServiceMonitorProcessor implements BeanPostProcessor {
@Override public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean.getClass().isAnnotationPresent(Service.class)) { return Proxy.newProxyInstance( bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), (proxy, method, args) -> { long start = System.currentTimeMillis(); try { return method.invoke(bean, args); } finally { long cost = System.currentTimeMillis() - start; if (cost > 500) { log.warn("慢调用:{}.{} cost={}ms", beanName, method.getName(), cost); } } } ); } return bean; } }
|
场景5:敏感字段脱敏
自动对返回对象中的敏感字段脱敏。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Component public class SensitiveDataProcessor implements BeanPostProcessor {
@Override public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean instanceof UserService) { return Proxy.newProxyInstance( bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), (proxy, method, args) -> { Object result = method.invoke(bean, args); if (result instanceof UserVO) { desensitize((UserVO) result); } return result; } ); } return bean; }
private void desensitize(UserVO user) { user.setPhone(user.getPhone().replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")); user.setIdCard(user.getIdCard().replaceAll("(\\d{4})\\d{10}(\\d{4})", "$1**********$2")); } }
|
四、为什么要代理?
核心原因:不修改源码的前提下增强功能
没有代理的世界——业务代码里到处穿插非业务逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public void createOrder() { log.info("开始创建订单"); checkPermission(); TransactionManager.begin(); try { orderDao.save(order); TransactionManager.commit(); } catch (Exception e) { TransactionManager.rollback(); throw e; } log.info("订单创建完成"); metrics.record("order.create", cost); }
|
有代理的世界——业务代码只写业务,增强逻辑由代理层统一处理:
1 2 3 4 5
| @Transactional @Log public void createOrder() { orderDao.save(order); }
|
代理解决了什么问题
| 不用代理 | 用代理 |
|---|
| 业务代码和非业务代码耦合 | 业务代码纯粹,只关注业务 |
| 每个方法重复写日志/事务/权限 | 声明式,一个注解搞定 |
| 改日志逻辑要改所有方法 | 改切面一处即可 |
| 无法对第三方类增强 | 代理可以包装任意对象 |
本质:开闭原则(OCP)——对扩展开放,对修改封闭。
为什么是代理而不是其他方式?
1. 为什么不直接改源码?
- 源码不可控:第三方库(MyBatis Mapper、Feign Client)你改不了
- 侵入性强:每个方法加逻辑,改一处动全局
- 违反OCP:增强功能应该扩展,不该修改
2. 为什么不用继承?
继承的问题:
- Java 单继承,只能增强一个维度
- 每加一个增强就要多一层子类,类爆炸
- UserService
- LogUserService ← 加日志
- TxUserService ← 加事务
- LogTxUserService ← 又加日志又加事务?组合爆炸
- 无法对 final 类增强
3. 为什么代理可以?
代理 = 组合 + 多态,完美替代继承
1
| 调用者 → 代理对象.invoke() → 前置增强 → 真实对象.method() → 后置增强 → 返回
|
可以无限嵌套(代理的代理的代理…):
1
| 日志代理 → 事务代理 → 权限代理 → 真实对象
|
每个代理只负责一个切面,自由组合,不爆炸
JDK 动态代理 vs CGLIB
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| UserService proxy = (UserService) Proxy.newProxyInstance( classLoader, new Class[]{UserService.class}, invocationHandler );
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback(methodInterceptor); UserService proxy = (UserService) enhancer.create();
|
| JDK 动态代理 | CGLIB |
|---|
| 原理 | 实现接口 | 继承目标类 |
| 要求 | 目标必须实现接口 | 目标不能是 final 类/方法 |
| 性能 | 生成快,调用稍慢(反射) | 生成慢,调用快(直接调用) |
| Spring 默认 | 有接口用 JDK | 无接口用 CGLIB |
| SpringBoot 默认 | — | 默认 CGLIB(spring.aop.proxy-target-class=true) |
Spring AOP 代理创建过程
- 容器启动,扫描 @Aspect / @Around 等切面定义
- 创建每个 Bean 时,BeanPostProcessor.postProcessAfterInitialization()
- AbstractAutoProxyCreator 判断该 Bean 是否需要代理
- 有匹配的切面 → 创建代理对象返回
- 无匹配切面 → 返回原始 Bean
- 代理对象替换原始 Bean 存入容器
- 后续注入的都是代理对象
- 调用时走代理链:日志 → 事务 → 权限 → 真实方法
1 2 3 4 5 6 7 8
| public Object postProcessAfterInitialization(Object bean, String beanName) { Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName); if (specificInterceptors != DO_NOT_PROXY) { return createProxy(bean.getClass(), specificInterceptors, bean); } return bean; }
|
代理失效的常见场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Service public class UserService { @Transactional public void methodA() { db.save(); }
public void methodB() { this.methodA(); }
@Autowired private UserService self;
public void methodB() { self.methodA(); } }
|
代理失效的场景:
this 内部调用(最常见)→ 绕过代理直接调用原始方法- 方法是 private / final / static → 代理无法重写
- 目标类是 final → CGLIB 无法生成子类
- 未被 Spring 管理 → 不是 Spring Bean,不走 BeanPostProcessor
- 异常被 catch 吞掉 →
@Transactional 感知不到异常,不回滚
五、代理对象 vs 真实对象
本质区别
- 真实对象:你写的类 new 出来的实例,只包含业务逻辑
- 代理对象:运行时动态生成的类的实例,持有真实对象的引用,在调用前后插入增强逻辑
1 2 3 4 5 6 7 8 9 10 11 12
| UserService real = new UserServiceImpl(); real.createUser(user);
UserService proxy = createProxy(real); proxy.createUser(user);
|
核心区别一览
| 维度 | 真实对象 | 代理对象 |
|---|
| 类 | UserServiceImpl | UserServiceImpl$$EnhancerBySpringCGLIB$$xxx |
| 创建方式 | new / Spring 反射 | BeanPostProcessor 运行时生成 |
| 方法执行 | 直接执行 | 拦截 → 增强 → 委托真实对象 |
| 包含逻辑 | 只有业务 | 业务 + 横切增强 |
| 对象身份 | 是目标类本身 | 是目标类的子类或实现类 |
| 容器中存的是 | 被代理对象替换 | 代理对象(真实对象被包裹在内) |
内存中的关系
1 2 3
| 容器中: userService → 代理对象(UserServiceImpl$$CGLIB$$123) ↓ 持有引用(target) 真实对象(UserServiceImpl)
|
1 2 3 4 5 6 7 8 9
| @Autowired private UserService userService;
System.out.println(userService.getClass().getName());
System.out.println(userService instanceof UserServiceImpl);
|
为什么容器里放代理对象而不是真实对象?
Spring 容器初始化流程:
new UserServiceImpl() → 创建真实对象- 属性注入
@Autowired → 真实对象属性填充完成 BeanPostProcessor.postProcessAfterInitialization()- 检测到
@Transactional 等切面 - 创建代理对象,包裹真实对象
- 返回代理对象
- 容器中
userService → 代理对象 ← 容器存的是代理对象 - 其他 Bean 注入
UserService 时 ← 拿到的也是代理对象
关键点:容器里只存代理对象,真实对象被代理对象内部持有,外部不可见。
代理对象调用链
1 2 3 4 5 6 7 8 9
| proxy.createUser() // 1. 调用代理方法 → CGLIB MethodInterceptor.intercept() // 2. 代理拦截 → ReflectiveMethodInvocation.proceed() // 3. 责任链执行 → 切面1: @Around 前置逻辑 // 4. 如: 开事务 → 切面2: @Before 逻辑 // 5. 如: 打日志 → target.createUser() // 6. 调用真实对象 ← 真正的业务 → 切面2: @After 逻辑 // 7. 如: 记录结果 → 切面1: @Around 后置逻辑 // 8. 如: 提交事务 ← 返回结果
|
this 调用为什么绕过代理
1 2 3 4 5 6 7 8 9 10
| @Service public class UserService {
@Transactional public void methodA() { }
public void methodB() { this.methodA(); } }
|
外部调用 userService.methodB() 的链路:
1 2 3 4 5 6 7
| 代理对象.methodB() → 拦截器.intercept() → 前置增强 → target.methodB() ← 进入真实对象 → this.methodA() ← this 是真实对象,不是代理对象! → 直接调用,不走拦截器 ← @Transactional 失效 → 后置增强
|
解决方式:
- 注入自身:
@Autowired private UserService self; self.methodA(); - AopContext:
((UserService) AopContext.currentProxy()).methodA(); - 拆分到不同类:把 methodA 移到另一个 Service
根本原因:this 指向真实对象而非代理对象,直接调用绕过了代理拦截。
JDK 动态代理 vs CGLIB 代理对象的区别
JDK 动态代理:
- 代理对象.getClass() →
com.sun.proxy.$Proxy23 - 代理对象
instanceof UserServiceImpl → false(不是子类,是接口的实现) - 代理对象
instanceof UserService → true(实现了接口)
CGLIB 代理:
- 代理对象.getClass() →
UserServiceImpl$$EnhancerBySpringCGLIB$$xxx - 代理对象
instanceof UserServiceImpl → true(是子类) - 代理对象
instanceof UserService → true
| JDK 代理对象 | CGLIB 代理对象 |
|---|
| 生成方式 | 实现接口 | 继承目标类 |
| 类名 | $ProxyN | Xxx$$CGLIB$$xxx |
| instanceof 目标类 | ❌ false | ✅ true |
| instanceof 接口 | ✅ true | ✅ true |
| 能否调目标类独有方法 | ❌ | ✅(但不走代理) |
怎么判断拿到的是代理还是真实对象?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| AopUtils.isAopProxy(bean) AopUtils.isJdkDynamicProxy(bean) AopUtils.isCglibProxy(bean)
bean.getClass().getName().contains("$Proxy") bean.getClass().getName().contains("$$Enhancer")
Object target = AopProxyUtils.getSingletonTarget(bean);
if (bean instanceof Advised) { Object target = ((Advised) bean).getTargetSource().getTarget(); }
|
六、其他 Post 接口
BeanFactoryPostProcessor vs BeanPostProcessor
| BeanFactoryPostProcessor | BeanPostProcessor |
|---|
| 作用时机 | Bean 实例化之前 | Bean 实例化之后 |
| 作用对象 | BeanDefinition(元数据) | Bean 实例 |
| 能做什么 | 修改 Bean 定义、属性值 | 修改/替换 Bean 实例 |
| 典型应用 | PropertyPlaceholderConfigurer | AOP 代理 |
1 2 3 4 5 6 7 8
| @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) { BeanDefinition bd = factory.getBeanDefinition("userService"); bd.getPropertyValues().add("timeout", 5000); } }
|
InstantiationAwareBeanPostProcessor
比 BeanPostProcessor 更细粒度,在实例化阶段介入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Component public class MyInstantiationProcessor implements InstantiationAwareBeanPostProcessor {
@Override public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) { if (beanClass == SpecialBean.class) { return new SpecialBeanProxy(); } return null; }
@Override public boolean postProcessAfterInstantiation(Object bean, String beanName) { return true; }
@Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { return pvs; } }
|
DestructionAwareBeanPostProcessor
销毁前的回调处理。
1 2 3 4 5 6 7 8 9
| @Component public class MyDestructionProcessor implements DestructionAwareBeanPostProcessor { @Override public void postProcessBeforeDestruction(Object bean, String beanName) { if (bean instanceof Disposable) { ((Disposable) bean).cleanup(); } } }
|
MergedBeanDefinitionPostProcessor
合并 Bean 定义后,收集注解元数据。
1 2 3 4 5 6 7 8 9
| @Component public class MyMergedDefinitionProcessor implements MergedBeanDefinitionPostProcessor { @Override public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { } }
|
七、所有 Post 接口执行顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| BeanFactoryPostProcessor.postProcessBeanFactory() ← 最早,改 BeanDefinition ↓ InstantiationAwareBPP.postProcessBeforeInstantiation() ← 实例化前,可替换实例 ↓ Constructor → new() ← 实例化 ↓ MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition() ↓ InstantiationAwareBPP.postProcessAfterInstantiation() ← 实例化后,可阻止属性注入 InstantiationAwareBPP.postProcessProperties() ← 修改注入属性 ↓ 属性注入 @Autowired / @Value ↓ BeanPostProcessor.postProcessBeforeInitialization() ← 初始化前 ↓ @PostConstruct / afterPropertiesSet / init-method ↓ BeanPostProcessor.postProcessAfterInitialization() ← 初始化后(AOP代理在这) ↓ Bean 就绪 ↓ DestructionAwareBPP.postProcessBeforeDestruction() ← 销毁前 @PreDestroy / destroy() / destroy-method
|
八、面试高频追问
Q1: BeanPostProcessor 和 BeanFactoryPostProcessor 区别?
BeanFactoryPostProcessor 在 Bean 实例化前执行,操作的是 BeanDefinition(配置元数据),比如修改属性值、改变作用域。BeanPostProcessor 在 Bean 实例化后执行,操作的是 Bean 实例本身,比如创建代理、增强功能。一个是改图纸,一个是改产品。
Q2: BeanPostProcessor 会影响所有 Bean 吗?
是的,容器中每个 Bean 创建时都会经过所有 BeanPostProcessor。所以实现中必须做类型判断,避免处理不需要的 Bean。同时要注意性能,不要在处理器中做耗时操作。
Q3: @Autowired 的实现原理?
底层是 AutowiredAnnotationBeanPostProcessor,它实现了 MergedBeanDefinitionPostProcessor(扫描 @Autowired 注解)和 SmartInstantiationAwareBeanPostProcessor(实际注入属性)。在 postProcessMergedBeanDefinition 阶段收集注入点,在 postProcessProperties 阶段完成注入。
Q4: 为什么 BeanPostProcessor 中不能直接注入其他 Bean?
BeanPostProcessor 本身的创建早于普通 Bean,如果通过 @Autowired 依赖其他 Bean,可能该 Bean 还未创建。正确做法是通过 BeanFactory.getBean() 延迟获取,或实现 Aware 接口获取。
Q5: 你项目中哪里用到了 BeanPostProcessor?
- 自定义注解校验:启动时检查必填配置项
- 慢接口监控:对 Service 层自动代理,记录超时调用
- 数据源代理:动态数据源切换
- 敏感字段脱敏:自动对返回值脱敏处理
九、一句话总结
Bean 生命周期 = 实例化 → 注入 → Aware → 前置 → 初始化 → 后置 → 使用 → 销毁。BeanPostProcessor 是 Spring 扩展的灵魂,AOP、@Autowired、@Async 都靠它实现。实际项目中常用于代理创建、注解扫描、监控埋点、自动校验等场景。