外观
Spring 的 Bean 的生命周期
⭐ 题目日期:
美团 - 2025/4/25
📝 题解:
Spring Bean 的生命周期指的是一个 Bean 从被创建、初始化、使用到最终被销毁的整个过程。Spring 容器(ApplicationContext
)精细地管理着这个过程,并提供了多个扩展点允许开发者介入自定义逻辑。
以下是 Spring Bean 生命周期的详细阶段:
Bean 定义 (
BeanDefinition
) 的加载与解析:- 容器启动时(如
ClassPathXmlApplicationContext
或AnnotationConfigApplicationContext
初始化),会读取配置文件(XML)、Java 配置类(@Configuration
)或扫描注解(@ComponentScan
)。 - 找到的所有 Bean 定义(通常是
BeanDefinition
对象)被加载到容器内部。BeanDefinition
包含了创建 Bean 所需的所有元数据:类名、作用域(scope
)、初始化方法、销毁方法、属性值、依赖关系等。
- 容器启动时(如
实例化 (Instantiation):
- 根据
BeanDefinition
中指定的类名(Class),容器使用构造器(默认无参构造器,或指定的构造器)来创建 Bean 的一个实例。 - 此时只是简单地调用构造方法
new Xxx()
,分配了内存空间,Bean 的属性都还是默认值(null
、0
、false
等),依赖也没有注入。
- 根据
属性填充/依赖注入 (Population / Dependency Injection):
- 容器根据
BeanDefinition
中的配置信息(如property
标签、@Autowired
、@Value
、@Resource
等注解),将值或对其他 Bean 的引用设置(注入)到新创建的 Bean 实例的属性或字段中。 - 这是实现 IoC(控制反转)的核心步骤。
- 容器根据
Aware 接口回调 (Aware Interfaces Callbacks):
- 如果 Bean 实现了 Spring 提供的各种
Aware
接口,容器会调用相应的方法,将相关的容器基础设施对象“通知”给 Bean。这是在属性注入之后,初始化回调之前执行的。 - 常用
Aware
接口:BeanNameAware
: 设置 Bean 在容器中的名字 (setBeanName(String name)
)。BeanFactoryAware
: 设置创建该 Bean 的BeanFactory
实例 (setBeanFactory(BeanFactory beanFactory)
)。提供对底层工厂的访问。ApplicationContextAware
: 设置创建该 Bean 的ApplicationContext
实例 (setApplicationContext(ApplicationContext applicationContext)
)。提供对完整应用上下文的访问(包含BeanFactory
的所有功能,还提供事件发布、资源加载等)。EnvironmentAware
: 设置应用环境 (Environment
) 对象 (setEnvironment(Environment environment)
)。用于访问配置属性和 profiles。ResourceLoaderAware
: 设置资源加载器 (ResourceLoader
) (setResourceLoader(ResourceLoader resourceLoader)
)。用于加载类路径或文件系统资源。ApplicationEventPublisherAware
: 设置事件发布器 (ApplicationEventPublisher
) (setApplicationEventPublisher(ApplicationEventPublisher publisher)
)。用于发布应用事件。MessageSourceAware
: 设置国际化消息源 (MessageSource
) (setMessageSource(MessageSource messageSource)
)。用于国际化。
- 如果 Bean 实现了 Spring 提供的各种
BeanPostProcessor 的前置处理 (
postProcessBeforeInitialization
):- 如果容器中存在实现了
BeanPostProcessor
接口的 Bean,容器会在 每个 Bean 的初始化回调方法(下一步)执行之前,调用所有BeanPostProcessor
的postProcessBeforeInitialization(Object bean, String beanName)
方法。 - 开发者可以通过实现此接口,在 Bean 初始化前对 Bean 实例进行修改、包装(如 AOP 代理)或执行某些逻辑。这是一个强大的全局扩展点。
- 如果容器中存在实现了
初始化回调 (Initialization Callbacks):
- 容器调用 Bean 定义的初始化方法。有三种主要方式指定:
- 实现
InitializingBean
接口: 实现afterPropertiesSet()
方法。容器在属性注入完成后调用此方法。 - XML 配置中指定
init-method
属性: 指定一个自定义的无参方法名。 - 使用
@PostConstruct
注解: 标注在一个自定义的无参方法上。这是现代 Spring 应用推荐的方式。
- 实现
- 注意: 如果同时使用了多种方式,调用顺序是:
@PostConstruct
注解的方法InitializingBean.afterPropertiesSet()
- 自定义的
init-method
指定的方法
- 在此阶段,Bean 的属性已注入完毕,可以执行一些自定义的初始化逻辑,如验证配置、建立数据库连接、启动线程等。
- 容器调用 Bean 定义的初始化方法。有三种主要方式指定:
BeanPostProcessor 的后置处理 (
postProcessAfterInitialization
):- 如果容器中存在实现了
BeanPostProcessor
接口的 Bean,容器会在 每个 Bean 的初始化回调方法(上一步)执行之后,调用所有BeanPostProcessor
的postProcessAfterInitialization(Object bean, String beanName)
方法。 - 这是另一个强大的全局扩展点。AOP 动态代理通常就是在这个阶段创建的。 开发者可以在这里对初始化完成的 Bean 进行最终处理或返回一个包装后的代理对象。
- 如果容器中存在实现了
Bean 就绪可用 (Ready for Use):
- 经过以上所有步骤,Bean 已经完全初始化完毕,其属性已注入,初始化逻辑已执行,并可能已被后置处理器包装(如代理)。此时 Bean 被放入容器(通常是单例池,如果是单例作用域),等待应用程序通过容器获取 (
getBean()
) 并使用。
- 经过以上所有步骤,Bean 已经完全初始化完毕,其属性已注入,初始化逻辑已执行,并可能已被后置处理器包装(如代理)。此时 Bean 被放入容器(通常是单例池,如果是单例作用域),等待应用程序通过容器获取 (
使用期 (In Use):
- 应用程序通过容器获取 Bean 实例并使用其功能。这是 Bean 生命周期的核心阶段。
销毁回调 (Destruction Callbacks): (当容器关闭时触发)
- 当 Spring 容器关闭时(如调用
ApplicationContext
的close()
方法),对于实现了销毁逻辑的 Bean(通常是单例 Bean,原型 Bean 的销毁由调用者管理),容器会调用其定义的销毁方法。同样有三种主要方式指定:- 实现
DisposableBean
接口: 实现destroy()
方法。 - XML 配置中指定
destroy-method
属性: 指定一个自定义的无参方法名。 - 使用
@PreDestroy
注解: 标注在一个自定义的无参方法上。推荐方式。
- 实现
- 注意: 如果同时使用了多种方式,调用顺序是:
@PreDestroy
注解的方法DisposableBean.destroy()
- 自定义的
destroy-method
指定的方法
- 在此阶段,Bean 应执行清理逻辑,如关闭数据库连接、停止线程、释放资源等。
- 当 Spring 容器关闭时(如调用
Bean 被垃圾回收 (Garbage Collection):
- 容器关闭后,不再持有 Bean 的引用。Bean 实例及其占用的资源最终由 JVM 的垃圾回收器回收。
图解简化流程:
[容器启动]
|
V
加载 & 解析 BeanDefinition --> [Bean 定义注册]
|
V
实例化 (new) ----------------> Bean 对象(空壳,属性未注入)
|
V
属性填充/依赖注入 ------------> Bean 对象(属性已赋值,依赖已注入)
|
V
Aware 接口回调 -------------> Bean 对象(已获知容器信息)
|
V
BeanPostProcessor.postProcessBeforeInitialization() -> 可修改/增强 Bean
|
V
初始化回调 (@PostConstruct / afterPropertiesSet() / init-method) -> 执行自定义初始化
|
V
BeanPostProcessor.postProcessAfterInitialization() -> 可修改/增强 Bean (AOP 代理在此创建)
|
V
[Bean 就绪] -----------------> 放入容器,等待使用
|
V
应用程序使用 Bean
|
V
[容器关闭]
|
V
销毁回调 (@PreDestroy / destroy() / destroy-method) -> 执行自定义清理
|
V
[Bean 销毁,资源释放]
|
V
[JVM GC 回收]
关键点总结:
BeanPostProcessor
是全局性的: 它们影响容器中所有的 Bean。是实现 AOP、事务管理、自定义注解处理等高级功能的基础。- Aware 接口提供基础设施访问: 让 Bean 感知到容器环境。
- 初始化回调 (
@PostConstruct
等) 用于 Bean 自身的初始化逻辑。 - 销毁回调 (
@PreDestroy
等) 用于 Bean 自身的清理逻辑。 - 作用域 (
scope
) 影响生命周期:singleton
(默认):容器启动时创建(或第一次请求时,取决于配置),容器关闭时销毁。prototype
:每次请求时创建新实例。容器不管理原型 Bean 的销毁! 由获取它的代码负责释放资源(或依赖容器的销毁机制触发其@PreDestroy
,但需注意原型 Bean 通常不会触发容器级的销毁回调)。request
/session
/application
(Web 环境):生命周期分别绑定到 HTTP 请求、用户会话、ServletContext。
- 理解顺序至关重要: 例如,依赖注入必须在 Aware 回调之前完成(因为 Aware 回调可能需要用到注入的属性),初始化回调必须在 BeanPostProcessor 的
postProcessBeforeInitialization
之后但在postProcessAfterInitialization
之前执行。
掌握 Spring Bean 的生命周期对于理解 Spring 的运作原理、解决依赖注入问题、实现自定义扩展(如通过 BeanPostProcessor
)以及正确管理资源(初始化/销毁)都至关重要。