Spring Boot 中 Bean 的生命周期详解
一、引言
在 Spring Boot 应用中,Bean 是构成应用程序的基础组件。理解 Bean 的生命周期对于开发高效、稳定的 Spring Boot 应用至关重要。本文将深入探讨 Spring Boot 中 Bean 的完整生命周期过程。
二、Bean 生命周期的基本概念
Bean 生命周期指的是从 Bean 的定义、创建、初始化、使用到销毁的整个过程。Spring 容器负责管理这些阶段,开发者可以通过各种方式干预这些过程。
三、Bean 生命周期的完整阶段
1. Bean 定义阶段
- 通过
@Component
、@Service
、@Repository
、@Controller
等注解定义 - 或通过 XML 配置、Java 配置类 (
@Configuration
) 定义
2. Bean 实例化阶段
容器通过以下方式创建 Bean 实例:
- 构造器实例化(最常用)
- 静态工厂方法
- 实例工厂方法
// 构造器实例化
@Component
public class MyBean {
public MyBean() {
System.out.println("1. 构造器执行 - 实例化阶段");
}
}
3. 属性赋值阶段
- 通过
@Autowired
、@Value
等注解注入依赖 - 或者通过 XML 配置注入
@Component
public class MyBean {
@Value("${my.property}")
private String property;
@Autowired
private AnotherBean anotherBean;
}
4. 初始化阶段
(1) Aware 接口回调
BeanNameAware
: 设置 Bean 的名称BeanFactoryAware
: 设置 BeanFactoryApplicationContextAware
: 设置 ApplicationContext
@Component
public class MyBean implements BeanNameAware {
@Override
public void setBeanName(String name) {
System.out.println("2. BeanNameAware 回调 - beanName: " + name);
}
}
(2) BeanPostProcessor 前置处理
postProcessBeforeInitialization
方法
(3) 初始化方法
@PostConstruct
注解的方法- 实现
InitializingBean
接口的afterPropertiesSet
方法 - XML 中配置的
init-method
@Component
public class MyBean {
@PostConstruct
public void init() {
System.out.println("3. @PostConstruct 初始化方法执行");
}
}
(4) BeanPostProcessor 后置处理
postProcessAfterInitialization
方法
5. 使用阶段
- Bean 完全初始化后,可以被应用程序使用
- 通过依赖注入或 ApplicationContext 获取
(1)@AutoConfigureBefore注解
@AutoConfigureBefore
指定当前自动配置类应该在某些其他自动配置类之前加载。
package com.zh.cn.config;
import com.zh.cn.controller.CoreController;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.startup.Tomcat;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* @Description:
* @author: zh
* @Create : 2025/4/11
* @Project_name : data
* @Version :
**/
@Slf4j
@Component
@AutoConfigureBefore(CoreConfig.class)
public class TestAConfig {
public TestAConfig(){
log.info("testAConfig 初始化");
}
@PostConstruct
public void init(){
log.info("testAConfig init 初始化完成");
}
@PreDestroy
public void destory(){
log.info("testAConfig destory 销毁释放资源");
}
public String getName(){
return "TestAConfig";
}
}
@AutoConfigureAfter注解
@AutoConfigureAfter指定当前自动配置类应该在某些其他自动配置类之后加载
package com.zh.cn.config;
import com.zh.cn.controller.CoreController;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.startup.Tomcat;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* @Description:
* @author: zh
* @Create : 2025/4/11
* @Project_name : data
* @Version :
**/
@Slf4j
@Component
@AutoConfigureAfter(CoreConfig.class)
public class TestAConfig {
public TestAConfig(){
log.info("testAConfig 初始化");
}
@PostConstruct
public void init(){
log.info("testAConfig init 初始化完成");
}
@PreDestroy
public void destory(){
log.info("testAConfig destory 销毁释放资源");
}
public String getName(){
return "TestAConfig";
}
}
6. 销毁阶段
(1) 销毁前回调
@PreDestroy
注解的方法- 实现
DisposableBean
接口的destroy
方法 - XML 中配置的
destroy-method
@Component
public class MyBean {
@PreDestroy
public void destroy() {
System.out.println("4. @PreDestroy 销毁方法执行");
}
}
(2) Bean 销毁
- 容器关闭时销毁 Bean 实例
四、完整的生命周期流程图
Bean定义 → 实例化 → 属性赋值 → Aware接口回调 → BeanPostProcessor前置处理 →
初始化方法(@PostConstruct/afterPropertiesSet/init-method) →
BeanPostProcessor后置处理 → 使用阶段 →
销毁方法(@PreDestroy/destroy/destroy-method) → Bean销毁
五、自定义生命周期干预方式
1. 实现特定接口
@Component
public class CustomBean implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() {
// 初始化逻辑
}
@Override
public void destroy() {
// 销毁逻辑
}
}
2. 使用注解
通过order注解可以指定初始化完成后的执行顺序
@Slf4j
@AutoConfigureBefore(TestAConfig.class)
@Component
public class TestBConfig implements InitializingBean, DisposableBean {
public TestBConfig(TestAConfig testAConfig){
System.out.println(testAConfig.getName());
log.info("testBConfig 初始化");
}
@Override
@Order(1)
public void afterPropertiesSet() throws Exception {
log.info("TestBConfig init afterPropertiesSet");
}
@PostConstruct
@Order(-1)
public void init(){
log.info("TestBConfig init 2 ");
}
@Override
public void destroy() throws Exception {
log.info("TestBConfig destory");
}
}
3. 使用 BeanPostProcessor
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// 前置处理逻辑
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
// 后置处理逻辑
return bean;
}
}
六、实际应用场景
- 资源初始化:数据库连接、线程池创建等
- 缓存预热:应用启动时加载热点数据
- 性能监控:记录 Bean 创建耗时
- 依赖检查:确保所有必要依赖已注入
- 资源清理:关闭文件句柄、释放网络连接等
七、常见问题与最佳实践
- 循环依赖问题:
- 避免构造器注入循环依赖
- 使用 setter/field 注入解决循环依赖
- 初始化顺序控制:
- 使用
@DependsOn
注解指定依赖关系 - 通过
@Order
控制 BeanPostProcessor 执行顺序
- 使用
- 性能优化:
- 将耗时的初始化操作延迟到真正需要时
- 考虑使用懒加载 (
@Lazy
)
- 测试考虑:
- 确保初始化逻辑不会影响单元测试
- 考虑使用 Mock 对象替代真实依赖
八、总结
Spring Boot 中 Bean 的生命周期是一个精心设计的过程,提供了多个扩展点供开发者干预。理解这些阶段和扩展点,能够帮助我们更好地控制组件的行为,构建更加健壮的应用。在实际开发中,应根据具体需求选择合适的干预方式,同时注意避免常见的陷阱和性能问题。
通过合理利用生命周期回调,我们可以实现更优雅的资源管理、更高效的性能优化和更可靠的错误处理,从而提升整个应用的质量和可维护性。