- 类的生命周期:Java 类什么时候被类加载器加载。
- Bean 的生命周期:Spring 什么时候把这个类变成 Bean,并完成注入、初始化、使用、销毁。
很多人会把这两层混在一起。更准确地说:Spring 管的是 Bean 生命周期,JVM 管的是类加载 。Spring 通常是在需要创建 Bean 时,基于 BeanDefinition 去解析并使用这个类。BeanFactory 负责按 BeanDefinition 返回 Bean 实例;单例 Bean 通常会被容器预先创建,原型 Bean 则通常在每次获取时创建。(Home)
总流程图
主线:
erlang
类加载
↓
Spring 扫描 / 解析配置,注册 BeanDefinition
↓
容器启动,执行 BeanFactoryPostProcessor
↓
实例化 Bean
↓
属性填充(依赖注入)
↓
Aware 回调
↓
BeanPostProcessor.before
↓
初始化方法
↓
BeanPostProcessor.after
↓
放入单例池 / 开始使用
↓
容器关闭
↓
销毁前处理
↓
销毁方法
这个顺序里,最容易考的就是中间那一段:实例化 → 注入 → Aware → beforeInit → init → afterInit → 使用 → destroy 。Spring 官方明确说明了初始化回调、销毁回调,以及 BeanPostProcessor 是在初始化前后起作用的。(Home)
一、类加载阶段:Bean 还没出生
这里先纠正一个很常见的说法:
不是"Spring 一启动就把所有类都加载了",而是 Spring 先读取配置、扫描组件、注册 BeanDefinition;真正到创建 Bean 时,才会解析并使用对应的类。
BeanFactory 的核心概念是:它持有很多 BeanDefinition,每个 BeanDefinition 描述"这个 Bean 怎么创建"。BeanDefinition 不等于 Bean 实例,它更像"施工图纸"。(Home)
你可以这样理解:
- 类加载 :JVM 把
.class文件加载进来 - BeanDefinition 注册:Spring 记住"这个类将来要作为 Bean"
- Bean 实例化 :Spring 真正
new出对象
所以从"类加载到销毁"这个角度看,第一步其实是:
1)类被加载到 JVM
可能是因为组件扫描、配置类解析、反射创建、依赖解析等原因触发。
但此时它还只是一个 Java 类,不一定已经是 Spring Bean。这个阶段更多是 JVM 行为,不是 Spring Bean 生命周期的核心部分。Spring 的核心生命周期真正开始于 BeanDefinition 已经存在,容器准备创建 Bean 。(Home)
二、注册 BeanDefinition:先立档,再造对象
Spring 容器启动时,会先做这些事:
2)读取配置元数据
来源可能是:
@Component、@Service、@Controller@Configuration+@Bean- XML
- Java 配置类
Spring 会把这些信息转成 BeanDefinition 注册到容器中。此时还没有真正创建 Bean,只是告诉容器:"将来这里要有一个 Bean,名字、类型、作用域、初始化方法、销毁方法都在这里。" BeanFactory 的官方定义就强调,它管理的是 BeanDefinition,并根据定义返回实例。(Home)
三、容器级后处理:Bean 出生前,先改"图纸"
在真正创建 Bean 之前,Spring 容器还会先处理一批"容器级扩展点"。
3)执行 BeanFactoryPostProcessor
这一类处理器不是改 Bean 实例,而是改 BeanDefinition 。
也就是 Bean 还没创建,就先把"施工图纸"改掉。
比如可能做这些事:
- 修改属性值
- 替换占位符
- 调整某些 Bean 定义
- 解析配置类
这一阶段非常重要,因为它发生在对象实例化之前。虽然你问的是 Bean 生命周期,但从完整过程看,这是 Bean 出生前的关键准备步骤。Spring 文档把这类机制归为容器扩展点。(Home)
四、实例化:Bean 真正被造出来
接下来才进入"Bean 本体生命周期"。
4)实例化 Bean
这一步就是把对象真正创建出来,常见方式有:
- 构造器实例化
- 工厂方法实例化
@Bean方法返回对象
你可以把这一步理解成:
Spring 先把"空壳对象"造出来。
注意,这时对象通常只是被创建出来,很多依赖还没注入完,也还没执行初始化逻辑。InstantiationAwareBeanPostProcessor 这类更高级的后处理器,甚至可以在目标 Bean 真正实例化前后介入。Spring 当前文档和 API 都明确提供了 postProcessBeforeInstantiation、postProcessAfterInstantiation 这样的扩展点。(Home)
五、属性填充:给空壳装配零件
5)依赖注入 / 属性填充
对象创建后,Spring 会给它注入依赖,例如:
@Autowired@Resource@Value- setter 注入
- 字段注入
- 构造器注入中剩余的依赖解析
这一步可以理解成"给空壳对象装零件"。
例如 UserService 里依赖 OrderService,Spring 会在这个阶段把 OrderService 注入进去。很多注解功能,本质上就是通过对应的后处理器实现的。Spring 官方文档也说明了:内部会使用 BeanPostProcessor 实现很多回调和注解处理。(Home)
六、Aware 回调:让 Bean 知道"自己在 Spring 里是谁"
6)执行 Aware 接口回调
如果 Bean 实现了这些接口,Spring 会把对应信息注入进去:
BeanNameAwareBeanClassLoaderAwareBeanFactoryAwareApplicationContextAware- 以及其他
Aware接口
比如:
- 让 Bean 知道自己的名字
- 拿到类加载器
- 拿到 BeanFactory
- 拿到 ApplicationContext
这一步的本质是:
让 Bean 获得 Spring 容器环境信息。
Spring 官方把这些 Aware 接口单独列为生命周期相关能力的一部分。(Home)
七、初始化前置处理:BeanPostProcessor.before
7)执行 postProcessBeforeInitialization
所有注册过的 BeanPostProcessor,都会在初始化方法之前过一遍当前 Bean。
官方定义很明确:
postProcessBeforeInitialization 是在任何初始化回调之前执行,比如 afterPropertiesSet() 或自定义 init-method 之前。(Home)
这一步常做的事:
- 检查 Bean
- 包装 Bean
- 处理注解
- 补充一些初始化前逻辑
你可以把它理解成:
Bean 已经造好了,零件也装好了,但正式启动前,先过一遍"质检"。
八、初始化:Bean 真正进入可用状态
8)执行初始化方法
这一步是 Bean 生命周期里最经典的一步。Spring 官方给出的初始化机制主要有三种:
@PostConstructInitializingBean.afterPropertiesSet()- 自定义
init-method
Spring 官方建议,在现代应用里优先考虑 @PostConstruct;如果不想用注解,也可以用 init-method。InitializingBean 能用,但会让业务代码和 Spring 接口耦合。(Home)
这一步通常做的事:
- 校验必要参数是否存在
- 打开连接
- 预热缓存
- 加载本地数据
- 做一些 Bean 真正可运行前的准备
你可以理解成:
前面只是"组装完成",到这里才是"开机启动"。
初始化顺序怎么记?
最常见的记法是:
@PostConstructafterPropertiesSet()- 自定义
init-method
Spring 官方文档专门说明了这些初始化回调机制会组合工作。(Home)
九、初始化后置处理:BeanPostProcessor.after
9)执行 postProcessAfterInitialization
初始化完成后,所有 BeanPostProcessor 再过一遍。
官方定义同样很清楚:
postProcessAfterInitialization 是在任何初始化回调之后执行。(Home)
这一阶段尤其重要,因为很多框架能力都在这里实现,比如:
- AOP 代理
- 事务代理
- 日志代理
- 权限代理
也就是说,容器里最终放进去的,不一定是原始 Bean,本可能是一个代理对象 。
这就是为什么你写的是 UserService,最后 Spring 给你的可能是一个代理过的 UserService。(Home)
你可以这样记:
beforeInit 是"初始化前检查"
afterInit 是"初始化后包装"
十、进入可用状态:Bean 开始对外服务
10)Bean 放入容器,进入使用阶段
如果是单例 Bean,经过上述流程后,通常会放进单例缓存池,后续别人拿到的就是这个 Bean。
如果是原型 Bean,则通常每次获取都会重新走创建流程,但 Spring 只负责创建,不负责完整销毁管理。BeanFactory 官方也强调了,它根据 BeanDefinition 和作用域语义来管理 Bean 实例。(Home)
如果 Bean 实现了 Lifecycle 等接口,它还可以参与容器整体的启动与停止过程。Spring 官方在生命周期说明中也单独提到了这一点。(Home)
十一、销毁前阶段:容器准备关闭
当容器关闭时,Bean 生命周期进入最后阶段。
11)执行销毁前处理
如果有 DestructionAwareBeanPostProcessor,Spring 会在真正销毁之前先调用它。Spring 当前 API 文档明确说明,这类处理器可以在 Bean 销毁前执行自定义逻辑。(Home)
这一步可以理解成:
正式关机前,再做一次清场和收尾。
十二、销毁阶段:释放资源
12)执行销毁方法
Spring 官方给出的销毁机制主要有三种:
@PreDestroyDisposableBean.destroy()- 自定义
destroy-method
官方同样建议优先考虑 @PreDestroy,这样不会和 Spring 接口强耦合。(Home)
这一阶段常做的事:
- 关闭数据库连接
- 关闭线程池
- 释放文件句柄
- 清理缓存
- 停止定时任务
你可以把它理解成:
Bean 下班前,把占用的资源都还回去。
十三、把整个生命周期串成一句人话
一个 Spring Bean 从头到尾,大致就是:
类先被 JVM 加载 → Spring 先登记成 BeanDefinition → 真正创建对象 → 注入依赖 → 回调各种 Aware 接口 → 初始化前处理 → 执行初始化方法 → 初始化后处理(可能生成代理)→ Bean 开始被使用 → 容器关闭时执行销毁前处理和销毁方法。 (Home)
十四、最容易考的"标准顺序"
如果你是为了面试,建议直接背这一版:
markdown
1. 加载 Bean 类
2. 注册 BeanDefinition
3. 执行 BeanFactoryPostProcessor
4. 实例化 Bean
5. 属性填充(依赖注入)
6. 调用 Aware 接口
7. BeanPostProcessor#postProcessBeforeInitialization
8. @PostConstruct
9. InitializingBean#afterPropertiesSet
10. 自定义 init-method
11. BeanPostProcessor#postProcessAfterInitialization
12. Bean 可用
13. 容器关闭
14. @PreDestroy
15. DisposableBean#destroy
16. 自定义 destroy-method
其中第 8 到 10 步和第 14 到 16 步,Spring 官方都明确支持,而且推荐优先用注解方式。(Home)
十五、你要特别注意的 4 个细节
1)BeanDefinition 不是 Bean
它只是"Bean 的说明书",不是实例。(Home)
2)AOP 代理通常发生在初始化后
也就是 postProcessAfterInitialization 之后,你拿到的 Bean 可能已经不是原始对象。(Home)
3)单例和原型生命周期不完全一样
单例 Bean 通常完整走创建和销毁;原型 Bean 通常只保证创建,销毁回调不由容器完整托管。这个差异来自 BeanFactory 的作用域语义。(Home)
4)@PostConstruct / @PreDestroy 通常比实现 Spring 接口更推荐
因为它们更少耦合,更符合官方建议。(Home)