Spring Bean 生命周期详解(超详细版)
目标:把 Bean 从“出生”到“死亡” 的全过程讲清楚,并把你能“插手改命”的关键扩展点都标出来。
1. 一句话总览
Spring Bean 的生命周期可以粗略理解成:
- 扫描/注册 BeanDefinition(只是“户口本”,不是对象)
- 实例化(new / 反射 / 工厂方法)
- 属性填充(依赖注入、@Autowired 等)
- 各种 Aware 回调(给你“上下文信息”)
- BeanPostProcessor 前置处理(初始化前拦一下)
- 初始化(@PostConstruct / InitializingBean / init-method)
- BeanPostProcessor 后置处理(初始化后拦一下,常用来创建 AOP 代理)
- 就绪可用
- 销毁(@PreDestroy / DisposableBean / destroy-method)
2. 先搞清楚:BeanDefinition vs Bean
BeanDefinition:描述 Bean 的“配方/元数据”,比如:
- class 是谁
- scope(singleton/prototype/…)
- 构造参数、属性值
- init-method / destroy-method
- 是否 lazy
- 是否 primary
- 依赖关系 depends-on 等
Bean:真正创建出来的 Java 对象。
很多“容器启动很快但第一次调用慢”的原因,就是前面只注册了 BeanDefinition,没有真正实例化(lazy 或者还没触发 getBean)。
3. 最经典的生命周期流程(以 singleton 为主)
下面按 Spring 容器 refresh 后的创建过程讲(最常见):
3.1 Bean 创建主流程(按时间顺序)
-
解析配置并注册 BeanDefinition
- XML / Java Config / @ComponentScan / ImportSelector / Registrar
- 典型扩展点:
BeanFactoryPostProcessor/BeanDefinitionRegistryPostProcessor
-
实例化 Instantiation
- 选择构造器:无参 / 有参(构造器注入)
- 也可能走 工厂方法:
@Bean、FactoryBean、Supplier - 典型扩展点:
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiationSmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors
-
设置属性 Populate Properties(依赖注入)
- 字段注入、setter 注入、@Autowired/@Resource、@Value 等
- 典型扩展点:
InstantiationAwareBeanPostProcessor#postProcessPropertiesAutowiredAnnotationBeanPostProcessor就在这里干活
-
Aware 回调(容器把“环境信息”塞给你)
常见顺序大致为:BeanNameAware#setBeanNameBeanClassLoaderAware#setBeanClassLoaderBeanFactoryAware#setBeanFactory- (在 ApplicationContext 场景下)
ApplicationContextAware#setApplicationContext - 还有:
EnvironmentAware、ResourceLoaderAware、ApplicationEventPublisherAware等
-
BeanPostProcessor:初始化前
BeanPostProcessor#postProcessBeforeInitialization- 常见用途:做一些初始化前的增强、字段处理、校验等
-
初始化 Initialization(三种方式都可能存在)
按“常见执行顺序”列一下(实际会受实现细节影响,但你可以这样记):@PostConstruct(JSR-250)InitializingBean#afterPropertiesSetinit-method(XML 或 @Bean(initMethod=“…”))
-
BeanPostProcessor:初始化后(非常关键)
BeanPostProcessor#postProcessAfterInitialization- AOP 代理(如
AbstractAutoProxyCreator)通常在这里把原对象“替换成代理对象” - 这就是为什么你注入进来的对象可能不是原类,而是代理
-
单例池缓存 & 对外可用
- singleton 会放入缓存(singletonObjects)
- 之后 getBean 基本就是从缓存取
-
销毁 Destroy(容器关闭时触发)
对 singleton 才有完整销毁回调;prototype 默认不由容器托管销毁(见后文)。常见销毁顺序(记住:也是“三种方式”):
@PreDestroyDisposableBean#destroydestroy-method
4. 用一张“顺序图”记住关键节点
BeanDefinition 已注册
|
v
[实例化] -> new / 构造器 / 工厂方法 / Supplier
|
v
[属性填充] -> DI / @Autowired / @Value
|
v
[Aware 回调] -> BeanNameAware/BeanFactoryAware/ApplicationContextAware...
|
v
[BPP BeforeInit] -> postProcessBeforeInitialization
|
v
[初始化] -> @PostConstruct -> afterPropertiesSet -> init-method
|
v
[BPP AfterInit] -> postProcessAfterInitialization (AOP代理常在这)
|
v
Bean 可用
|
v
容器关闭
|
v
[销毁] -> @PreDestroy -> destroy -> destroy-method
5. 你能“插手”的扩展点(超级重要)
5.1 BeanFactoryPostProcessor(创建 Bean 之前改“配方”)
- 作用:修改 BeanDefinition(还没实例化对象)
- 典型实现:
PropertySourcesPlaceholderConfigurer、自定义占位符处理等
@Component
public class MyBFPP implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) {
// 可以修改 BeanDefinition,例如改 scope、改属性值等
}
}
记忆法:BFPP = Before Factory creates Beans(在工厂真正造对象前动手)。
5.2 BeanPostProcessor(创建 Bean 过程中改“对象”)
- 作用:对象级别增强(初始化前后)
- 典型实现:
AutowiredAnnotationBeanPostProcessor、AOP 的自动代理创建器
@Component
public class MyBPP implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
记忆法:BPP = Bean 的“出厂质检+改装”流程。
5.3 InstantiationAwareBeanPostProcessor(更早、甚至能“拦截实例化”)
- 可以在实例化前返回代理对象,直接跳过默认实例化过程
- 常用于某些框架的高级注入、代理生成
6. 初始化与销毁:到底谁先谁后?
6.1 初始化(通常你关心的)
常见执行链路(便于记忆):
@PostConstructafterPropertiesSetinit-methodpostProcessAfterInitialization(可能返回代理)
注意:
@PostConstruct要求对应的 BPP 生效(通常是CommonAnnotationBeanPostProcessor)。- 如果你发现
@PostConstruct不执行,先怀疑:容器环境/依赖是否启用、Bean 是否真的被创建。
6.2 销毁
@PreDestroyDisposableBean#destroydestroy-method
7. 不同 scope 的差异(很容易踩坑)
7.1 singleton(默认)
- 容器启动/首次使用时创建(取决于 lazy)
- 容器关闭时会走完整销毁流程
7.2 prototype(每次 getBean 都 new 一个)
- 容器只负责“创建 + 初始化”
- 默认不负责销毁(不会自动调用 @PreDestroy / destroy-method)
- 如果你创建了 prototype 并且持有外部资源(线程池/连接),你要自己负责释放
7.3 request / session / application(Web 场景)
- 生命周期和 HTTP 请求、会话绑定
- 销毁由 Web 容器/上下文驱动
8. Bean 的“三级缓存”与循环依赖(面试+实战都爱问)
8.1 为什么会有三级缓存?
为了处理 singleton 的循环依赖(A 依赖 B,B 又依赖 A),Spring 引入:
- 一级缓存:
singletonObjects(成熟成品) - 二级缓存:
earlySingletonObjects(早期引用) - 三级缓存:
singletonFactories(ObjectFactory,用来生成早期引用/代理)
核心思路:
- 先把“能返回早期引用的工厂”放进三级缓存
- 需要时提前暴露一个早期对象引用解决循环依赖
- 之后对象初始化完成,再放到一级缓存
8.2 哪些循环依赖能解决?
- singleton + setter/字段注入:通常可解
- 构造器注入形成循环依赖:通常不可解(因为实例都造不出来)
- prototype 循环依赖:通常不可解(每次都新建,没法缓存)
9. FactoryBean:别把它当普通 Bean
- 普通 Bean:
getBean("userService")返回 userService 实例 FactoryBean:getBean("xxxFactoryBean")默认返回 它生产的对象- 想拿到 FactoryBean 自己:
getBean("&xxxFactoryBean")
用途:复杂对象创建(例如 MyBatis 的 MapperFactoryBean)。
10. ApplicationContext 多出来的“容器事件阶段”
如果你用的是 ApplicationContext(大部分 Spring Boot / Spring 项目都是):
ContextRefreshedEvent:容器 refresh 完成ContextClosedEvent:容器关闭
你还会见到:
ApplicationRunner/CommandLineRunner(Spring Boot 启动后执行)SmartLifecycle(更精细控制启动/停止阶段)
这些属于“容器生命周期”,不完全等于单个 Bean 的生命周期,但经常一起被问。
11. 一个最小可运行示例:观察完整顺序
@Component
public class LifeDemo implements BeanNameAware, BeanFactoryAware,
InitializingBean, DisposableBean {
public LifeDemo() {
System.out.println("1) 构造方法");
}
@Autowired
public void setXxx(SomeDep dep) {
System.out.println("2) 属性注入/依赖注入");
}
@Override
public void setBeanName(String name) {
System.out.println("3) BeanNameAware: " + name);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
System.out.println("4) BeanFactoryAware");
}
@PostConstruct
public void postConstruct() {
System.out.println("5) @PostConstruct");
}
@Override
public void afterPropertiesSet() {
System.out.println("6) InitializingBean.afterPropertiesSet");
}
public void initMethod() {
System.out.println("7) init-method");
}
@PreDestroy
public void preDestroy() {
System.out.println("8) @PreDestroy");
}
@Override
public void destroy() {
System.out.println("9) DisposableBean.destroy");
}
public void destroyMethod() {
System.out.println("10) destroy-method");
}
}
如果你用 @Bean 注册它:
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public LifeDemo lifeDemo() {
return new LifeDemo();
}
12. 常见坑点(踩过一次就记住)
-
@PostConstruct 不执行
- Bean 没有真正创建(lazy 或从未被引用)
- 对应的处理器没生效(环境/依赖/配置)
- Bean 被代理替换导致你观察对象不对(但方法仍会在目标对象上执行)
-
prototype 资源泄漏
- prototype 不自动销毁,你必须手动释放
-
AOP 代理导致 this 调用失效
- 在同一个类里
this.xxx()不会走代理,事务/切面可能不生效 - 解决:拆分类、通过注入自身代理、或用
AopContext(不推荐滥用)
- 在同一个类里
-
构造器循环依赖
- 改为 setter/字段注入,或者重构依赖关系
13. 速记卡(面试一分钟版本)
- BeanDefinition 先注册,Bean 后创建
- 创建顺序:实例化 → 属性填充 → Aware → BPP BeforeInit → 初始化(@PostConstruct / afterPropertiesSet / init-method) → BPP AfterInit(AOP代理) → 可用
- 销毁顺序:@PreDestroy → DisposableBean.destroy → destroy-method
- prototype 不托管销毁
- 循环依赖:singleton setter 通常可解,构造器/ prototype 通常不可解
- AOP 通常在
postProcessAfterInitialization生成代理
14. 你可以怎么用它(实战建议)
- 需要“依赖注入完成后初始化”:优先用
@PostConstruct - 需要“对外部资源做关闭”:singleton 用
@PreDestroy;prototype 自己管理 - 需要“改 Bean 配方/批量改属性”:用
BeanFactoryPostProcessor - 需要“统一做对象增强/代理”:用
BeanPostProcessor
1971

被折叠的 条评论
为什么被折叠?



