深入理解Spring Bean的生命周期
在Spring框架中,Bean是核心概念之一。简单来说,Bean就是由Spring IoC容器管理的对象。但你是否好奇,一个Bean从被定义到最终被销毁,经历了哪些过程?理解Bean的生命周期,不仅能帮助我们更好地使用Spring,还能在关键时刻(如资源初始化、销毁)进行自定义操作。今天,我们就来详细拆解Spring Bean的完整生命周期。
一、Bean生命周期概览
Spring Bean的生命周期可以概括为“从创建到销毁”的全过程,涉及IoC容器的多个核心操作。整体来看,可分为以下四个大阶段:
- Bean的定义阶段:IoC容器加载Bean的配置信息(如XML、注解),并在容器中注册Bean的元数据。
- Bean的创建与初始化阶段:容器根据元数据创建Bean实例,注入依赖,并执行初始化操作。
- Bean的使用阶段:Bean处于可用状态,供应用程序调用。
- Bean的销毁阶段:容器关闭时,Bean执行销毁操作,释放资源。
其中,创建与初始化阶段是最复杂的,包含多个关键步骤和扩展点。接下来,我们将逐步拆解每个阶段的细节。
二、详细阶段拆解
1. 阶段一:Bean的定义阶段
在这个阶段,Spring IoC容器首先需要“知道”哪些Bean需要被管理。具体来说,容器会加载并解析Bean的配置信息(如@Component
注解、<bean>
标签),然后将这些信息转换为容器内部的“Bean定义对象”(BeanDefinition
),并注册到BeanDefinitionRegistry
中。
关键操作:
- 读取配置:容器扫描指定路径(如
@ComponentScan
)或解析XML文件,获取Bean的类名、属性、依赖、作用域(scope)等信息。 - 注册Bean定义:将解析后的
BeanDefinition
存入容器,此时还未创建Bean实例,只是记录了“如何创建Bean”的元数据。
举例:
当我们用@Component
注解标记一个类时,Spring会在启动时扫描到该类,并生成对应的BeanDefinition
,注册到容器中。
2. 阶段二:Bean的创建与初始化阶段(核心)
这是Bean生命周期中最核心的阶段,包含实例化、依赖注入、初始化等关键步骤。我们按顺序拆解:
步骤1:实例化Bean(Instantiation)
容器根据BeanDefinition
中的信息(如类名),通过反射创建Bean的实例对象(内存中分配空间)。此时的Bean还只是一个“空壳”,属性尚未赋值。
- 单例Bean(scope=“singleton”):在容器启动时(或首次被请求时,取决于
lazy-init
配置)实例化,整个容器中只存在一个实例。 - 原型Bean(scope=“prototype”):每次被请求时(如
getBean()
)才实例化,容器不管理其生命周期。
步骤2:属性注入(Populate Properties)
实例化后,容器会根据BeanDefinition
中的依赖信息(如@Autowired
、<property>
标签),为Bean的属性赋值(注入依赖)。依赖的Bean可能是已创建的,也可能需要先触发依赖Bean的生命周期。
举例:
如果Bean A依赖Bean B,容器会先确保B已实例化并注入到A中:
@Component
public class BeanA {
@Autowired
private BeanB beanB; // 注入BeanB
}
步骤3:执行Aware接口回调(若实现)
Spring提供了一系列Aware
接口,用于让Bean感知容器的信息(如Bean名称、容器本身)。如果Bean实现了这些接口,容器会在此时调用对应的回调方法:
BeanNameAware
:注入当前Bean在容器中的名称(setBeanName(String name)
)。BeanFactoryAware
:注入当前Bean所在的BeanFactory(setBeanFactory(BeanFactory factory)
)。ApplicationContextAware
:注入当前应用的ApplicationContext(setApplicationContext(ApplicationContext context)
)。
举例:
@Component
public class MyBean implements BeanNameAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name; // 容器注入Bean名称
System.out.println("当前Bean名称:" + beanName);
}
}
步骤4:执行BeanPostProcessor的前置处理(Before Initialization)
BeanPostProcessor
是Spring的核心扩展接口,被称为“Bean后置处理器”。它可以在Bean初始化前后对Bean进行增强处理(如AOP代理)。
容器会遍历所有注册的BeanPostProcessor
,调用其postProcessBeforeInitialization
方法,对Bean进行前置处理。
举例:
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化前处理:" + beanName);
return bean; // 可返回增强后的Bean(如代理对象)
}
}
步骤5:执行初始化方法(Initialization)
初始化是Bean准备就绪前的最后一步,用于执行自定义的初始化逻辑(如资源加载、连接建立)。有三种方式定义初始化方法,执行顺序如下:
- 实现InitializingBean接口:重写
afterPropertiesSet()
方法(容器在属性注入完成后调用)。 - @PostConstruct注解:标记在方法上,容器会在属性注入后自动调用。
- 自定义init-method:在配置中指定(如
@Bean(initMethod = "myInit")
或XML的init-method
属性)。
执行顺序:@PostConstruct
→ InitializingBean.afterPropertiesSet()
→ 自定义init-method。
举例:
@Component
public class MyBean implements InitializingBean {
// 方式1:@PostConstruct
@PostConstruct
public void postConstruct() {
System.out.println("执行@PostConstruct");
}
// 方式2:InitializingBean
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行afterPropertiesSet");
}
// 方式3:自定义init-method(需在@Bean中指定)
public void myInit() {
System.out.println("执行自定义init-method");
}
}
步骤6:执行BeanPostProcessor的后置处理(After Initialization)
容器再次遍历BeanPostProcessor
,调用其postProcessAfterInitialization
方法,对Bean进行后置处理。AOP代理通常在此步骤生成(如通过@Transactional
创建事务代理)。
举例:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化后处理:" + beanName);
return bean; // 若返回代理对象,后续使用的就是代理Bean
}
3. 阶段三:Bean的使用阶段
经过上述步骤后,Bean已完全初始化,处于“可用”状态。此时,应用程序可以通过ApplicationContext.getBean()
获取Bean,并调用其方法。
- 单例Bean:一直存在于容器中,直到容器关闭。
- 原型Bean:每次获取都是新实例,容器不跟踪其后续状态。
4. 阶段四:Bean的销毁阶段
当容器关闭时(如ApplicationContext.close()
),单例Bean会进入销毁阶段(原型Bean不被容器管理,不会执行销毁流程)。销毁阶段的核心是释放资源(如关闭连接、删除临时文件)。
销毁方法的定义方式与初始化类似,执行顺序如下:
- @PreDestroy注解:标记在方法上,容器关闭前调用。
- 实现DisposableBean接口:重写
destroy()
方法。 - 自定义destroy-method:在配置中指定(如
@Bean(destroyMethod = "myDestroy")
或XML的destroy-method
属性)。
执行顺序:@PreDestroy
→ DisposableBean.destroy()
→ 自定义destroy-method。
举例:
@Component
public class MyBean implements DisposableBean {
// 方式1:@PreDestroy
@PreDestroy
public void preDestroy() {
System.out.println("执行@PreDestroy");
}
// 方式2:DisposableBean
@Override
public void destroy() throws Exception {
System.out.println("执行destroy");
}
// 方式3:自定义destroy-method
public void myDestroy() {
System.out.println("执行自定义destroy-method");
}
}
三、生命周期执行顺序验证
为了更直观地理解,我们通过一个完整示例展示Bean生命周期的执行顺序:
1. 定义Bean及相关组件
// 自定义Bean
@Component
public class LifeCycleBean implements BeanNameAware, InitializingBean, DisposableBean {
private String name;
// 构造方法(实例化时调用)
public LifeCycleBean() {
System.out.println("1. 实例化:调用构造方法");
}
// setter方法(属性注入)
public void setName(String name) {
this.name = name;
System.out.println("2. 属性注入:name = " + name);
}
// BeanNameAware回调
@Override
public void setBeanName(String name) {
System.out.println("3. BeanNameAware:Bean名称 = " + name);
}
// @PostConstruct
@PostConstruct
public void postConstruct() {
System.out.println("4. @PostConstruct");
}
// InitializingBean
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("5. InitializingBean.afterPropertiesSet");
}
// 自定义init-method(需在配置中指定)
public void myInit() {
System.out.println("6. 自定义init-method");
}
// @PreDestroy
@PreDestroy
public void preDestroy() {
System.out.println("8. @PreDestroy");
}
// DisposableBean
@Override
public void destroy() throws Exception {
System.out.println("9. DisposableBean.destroy");
}
// 自定义destroy-method
public void myDestroy() {
System.out.println("10. 自定义destroy-method");
}
}
// 自定义BeanPostProcessor
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LifeCycleBean) {
System.out.println("3.5 BeanPostProcessor前置处理");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LifeCycleBean) {
System.out.println("7. BeanPostProcessor后置处理");
}
return bean;
}
}
// 配置类(指定init-method和destroy-method)
@Configuration
@ComponentScan("com.example")
public class AppConfig {
@Bean(initMethod = "myInit", destroyMethod = "myDestroy")
public LifeCycleBean lifeCycleBean() {
LifeCycleBean bean = new LifeCycleBean();
bean.setName("测试Bean"); // 手动注入属性(模拟XML配置)
return bean;
}
}
// 启动类
public class Main {
public static void main(String[] args) {
// 启动容器
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("=== Bean已可用 ===");
// 关闭容器(触发销毁)
((AnnotationConfigApplicationContext) context).close();
}
}
2. 执行结果
1. 实例化:调用构造方法
2. 属性注入:name = 测试Bean
3. BeanNameAware:Bean名称 = lifeCycleBean
3.5 BeanPostProcessor前置处理
4. @PostConstruct
5. InitializingBean.afterPropertiesSet
6. 自定义init-method
7. BeanPostProcessor后置处理
=== Bean已可用 ===
8. @PreDestroy
9. DisposableBean.destroy
10. 自定义destroy-method
结果完全符合我们前面梳理的顺序,验证了Bean生命周期的各个阶段。
四、单例与原型Bean的生命周期差异
特性 | 单例Bean(singleton) | 原型Bean(prototype) |
---|---|---|
实例化时机 | 容器启动时(或首次请求,取决于lazy-init) | 每次请求时(getBean() ) |
容器管理范围 | 全程管理(创建→初始化→销毁) | 只管理创建与初始化,不管理销毁 |
销毁阶段 | 容器关闭时执行销毁方法 | 不执行销毁方法(需手动处理) |
五、总结
Spring Bean的生命周期看似复杂,但核心是“从定义到销毁”的有序流程。关键节点包括:
- 定义:注册Bean元数据;
- 创建:实例化→属性注入;
- 初始化:Aware回调→BeanPostProcessor前置→初始化方法→BeanPostProcessor后置;
- 使用:Bean可用;
- 销毁:销毁方法执行。
理解生命周期的意义在于,我们可以在关键节点插入自定义逻辑(如@PostConstruct
初始化资源、BeanPostProcessor
实现AOP),让Bean更好地适配业务需求。
希望本文能帮助你彻底搞懂Spring Bean的生命周期!如果有疑问,欢迎在评论区交流~