一文详解Spring Bean的生命周期
一文详解Spring Bean的生命周期
本文详细讲解了Spring框架中Bean的生命周期,包括实例化、属性赋值、初始化、使用中和销毁五个阶段。通过源码分析和单元测试的方式,深入描述了每个阶段的具体实现,并提供了具体的代码示例。此外,还介绍了Aware接口的作用以及init-method和destroy-method的调用时机。
Bean生命周期概述
Bean的生命周期大致分为五个阶段:
实例化:Spring首先使用构造方法或者工厂方法创建一个Bean的实例。在这个阶段,Bean只是一个空的Java对象,还未设置任何属性。
属性赋值:Spring将配置文件中的属性值或依赖的Bean注入到该Bean中。这个过程称为依赖注入,确保Bean所需的所有依赖都被注入。
初始化:Spring调用afterPropertiesSet方法,或通过配置文件指定的init-method方法,完成初始化。
使用中:Bean准备好可以使用了。
销毁:在容器关闭时,Spring会调用destroy方法,完成Bean的清理工作。
源码分析
接下来从源码角度讲解Bean的生命周期:
实例化:Spring容器根据Bean的定义创建Bean的实例,相当于执行构造方法,也就是new一个对象。
属性赋值:相当于执行setter方法为字段赋值。
初始化:初始化阶段允许执行自定义的逻辑,比如设置某些必要的属性值、开启资源、执行预加载操作等,以确保Bean在使用之前是完全配置好的。
销毁:相当于执行null,释放资源。
可以在源码AbstractAutowireCapableBeanFactory
中的doCreateBean
方法中,看到Bean的前三个生命周期:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 实例化阶段
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
...
Object exposedObject = bean;
try {
// 属性赋值阶段
this.populateBean(beanName, mbd, instanceWrapper);
// 初始化阶段
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
...
}
...
}
源码位置如下:
至于销毁,是在容器关闭的时候调用的,详见ConfigurableApplicationContext
的close
方法。
单元测试演示
接下来在一个已有的Spring Boot项目中通过单元测试的形式来展示Spring Bean的生命周期。
创建LifecycleDemoBean类
public class LifecycleDemoBean implements InitializingBean, DisposableBean {
// 使用@Value注解注入属性值,这里演示了如何从配置文件中读取值
// 如果配置文件中没有定义lifecycle.demo.bean.name,则使用默认值"default name"
@Value("${lifecycle.demo.bean.name:default name}")
private String name;
// 构造方法:在Bean实例化时调用
public LifecycleDemoBean() {
System.out.println("LifecycleDemoBean: 实例化");
}
// 属性赋值:Spring通过反射调用setter方法为Bean的属性注入值
public void setName(String name) {
System.out.println("LifecycleDemoBean: 属性赋值");
this.name = name;
}
// 使用@PostConstruct注解的方法:在Bean的属性赋值完成后调用,用于执行初始化逻辑
@PostConstruct
public void postConstruct() {
System.out.println("LifecycleDemoBean: @PostConstruct(初始化)");
}
// 实现InitializingBean接口:afterPropertiesSet方法在@PostConstruct注解的方法之后调用
// 用于执行更多的初始化逻辑
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("LifecycleDemoBean: afterPropertiesSet(InitializingBean)");
}
// 自定义初始化方法:在XML配置或Java配置中指定,执行特定的初始化逻辑
public void customInit() {
System.out.println("LifecycleDemoBean: customInit(自定义初始化方法)");
}
// 使用@PreDestroy注解的方法:在容器销毁Bean之前调用,用于执行清理工作
@PreDestroy
public void preDestroy() {
System.out.println("LifecycleDemoBean: @PreDestroy(销毁前)");
}
// 实现DisposableBean接口:destroy方法在@PreDestroy注解的方法之后调用
// 用于执行清理资源等销毁逻辑
@Override
public void destroy() throws Exception {
System.out.println("LifecycleDemoBean: destroy(DisposableBean)");
}
// 自定义销毁方法:在XML配置或Java配置中指定,执行特定的清理逻辑
public void customDestroy() {
System.out.println("LifecycleDemoBean: customDestroy(自定义销毁方法)");
}
}
实例化阶段
实例化是创建Bean实例的过程,即在内存中为Bean对象分配空间。这一步是通过调用Bean的构造方法完成的。
public LifecycleDemoBean() {
System.out.println("LifecycleDemoBean: 实例化");
}
在这里,当Spring创建LifecycleDemoBean
的实例时,会调用其无参数的构造方法,这个过程就是实例化。
属性赋值阶段
在实例化之后,Spring将根据Bean定义中的配置信息,通过反射机制为Bean的属性赋值。
@Value("${lifecycle.demo.bean.name:default name}")
private String name;
public void setName(String name) {
System.out.println("LifecycleDemoBean: 属性赋值");
this.name = name;
}
@Value
注解和setter方法体现了属性赋值的过程。@Value
注解让Spring注入配置值(或默认值),setter方法则是属性赋值的具体操作。
初始化阶段
初始化阶段允许执行自定义的初始化逻辑,比如检查必要的属性是否已经设置、开启资源等。Spring提供了多种方式来配置初始化逻辑。
- 使用
@PostConstruct
注解的方法
@PostConstruct
public void postConstruct() {
System.out.println("LifecycleDemoBean: @PostConstruct(初始化)");
}
@PostConstruct
注解的方法在Bean的所有属性都被赋值后,且用户自定义的初始化方法之前调用。
- 实现
InitializingBean
接口的afterPropertiesSet
方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("LifecycleDemoBean: afterPropertiesSet(InitializingBean)");
}
afterPropertiesSet
方法提供了另一种初始化Bean的方式,也是在所有属性赋值后调用。
- 自定义初始化方法
public void customInit() {
System.out.println("LifecycleDemoBean: customInit(自定义初始化方法)");
}
需要在配置类中指定初始化方法:
@Bean(initMethod = "customInit")
public LifecycleDemoBean lifecycleDemoBean() {
return new LifecycleDemoBean();
}
销毁阶段
销毁阶段允许执行自定义的销毁逻辑,比如释放资源。类似于初始化阶段,Spring也提供了多种方式来配置销毁逻辑。
- 使用
@PreDestroy
注解的方法
@PreDestroy
public void preDestroy() {
System.out.println("LifecycleDemoBean: @PreDestroy(销毁前)");
}
@PreDestroy
注解的方法在Bean被销毁前调用。
- 实现
DisposableBean
接口的destroy
方法
@Override
public void destroy() throws Exception {
System.out.println("LifecycleDemoBean: destroy(DisposableBean)");
}
destroy
方法提供了另一种销毁Bean的方式,也是在Bean被销毁前调用。
- 自定义销毁方法
public void customDestroy() {
System.out.println("LifecycleDemoBean: customDestroy(自定义销毁方法)");
}
需要在配置类中指定销毁方法:
@Bean(destroyMethod = "customDestroy")
public LifecycleDemoBean lifecycleDemoBean() {
return new LifecycleDemoBean();
}
注册Bean并指定自定义初始化方法和销毁方法
@Configuration
public class LifecycleDemoConfig {
@Bean(initMethod = "customInit", destroyMethod = "customDestroy")
public LifecycleDemoBean lifecycleDemoBean() {
return new LifecycleDemoBean();
}
}
编写单元测试
@SpringBootTest
public class LifecycleDemoTest {
@Autowired
private ApplicationContext context;
@Test
public void testBeanLifecycle() {
System.out.println("获取LifecycleDemoBean实例...");
LifecycleDemoBean bean = context.getBean(LifecycleDemoBean.class);
}
}
运行单元测试,查看控制台输出:
LifecycleDemoBean: 实例化
LifecycleDemoBean: @PostConstruct(初始化)
LifecycleDemoBean: afterPropertiesSet(InitializingBean)
LifecycleDemoBean: customInit(自定义初始化方法)
获取LifecycleDemoBean实例...
LifecycleDemoBean: @PreDestroy(销毁前)
LifecycleDemoBean: destroy(DisposableBean)
LifecycleDemoBean: customDestroy(自定义销毁方法)
Aware接口的作用
通过实现Aware接口,Bean可以获取Spring容器的相关信息,如BeanFactory、ApplicationContext等。常见Aware接口有:
接口 | 作用 |
---|---|
BeanNameAware | 获取当前Bean的名称。 |
BeanFactoryAware | 获取当前Bean所在的BeanFactory实例,可以直接操作容器。 |
ApplicationContextAware | 获取当前Bean所在的ApplicationContext实例。 |
EnvironmentAware | 获取Environment对象,用于获取配置文件中的属性或环境变量。 |
ServletContextAware | 在Web环境下获取ServletContext实例,访问Web应用上下文。 |
ResourceLoaderAware | 获取ResourceLoader对象,用于加载资源文件(如类路径文件或URL)。 |
init-method和destroy-method的调用时机
- init-method在Bean初始化阶段调用,依赖注入完成后且postProcessBeforeInitialization调用之后执行。
- destroy-method在Bean销毁阶段调用,容器关闭时调用。
本文原文来自CSDN