深入理解 Spring Bean 生命周期:从实例化到销毁

在 Spring 框架中,Bean 的生命周期是理解容器管理机制的核心。本文将通过图示和代码示例,详细解析 Spring Bean 从创建到销毁的完整流程,并解答常见疑问:是否可以在初始化前跳过属性赋值?

Bean 生命周期概览

Spring Bean 的生命周期大致分为以下几个阶段:

  1. 实例化:通过构造方法创建 Bean 对象。
  2. 属性赋值:为 Bean 的依赖和属性注入值。
  3. BeanNameAware:设置 Bean 名称。
  4. BeanFactoryAware:设置 BeanFactory。
  5. ApplicationContextAware:设置 ApplicationContext。
  6. 初始化前处理BeanPostProcessor.postProcessBeforeInitialization
  7. @PostConstruct 注解方法:初始化逻辑执行。
  8. InitializingBean.afterPropertiesSet:属性设置完成后的回调。
  9. 自定义 init 方法 :通过 @Bean(initMethod) 指定。
  10. 初始化后处理BeanPostProcessor.postProcessAfterInitialization
  11. Bean 使用阶段:Bean 已准备就绪,可用于业务逻辑。
  12. @PreDestroy 注解方法:销毁前回调。
  13. DisposableBean.destroy:销毁方法执行。
  14. 自定义 destroy 方法 :通过 @Bean(destroyMethod) 指定。

代码示例

1. 主配置类

less 复制代码
@Configuration
@ComponentScan("com.example.lifecycle")
public class AppConfig {
    @Bean(initMethod = "customInit", destroyMethod = "customDestroy")
    public ExampleBean exampleBean() {
        return new ExampleBean();
    }
}

2. Bean 生命周期类

csharp 复制代码
public class ExampleBean implements
        BeanNameAware,
        BeanFactoryAware,
        ApplicationContextAware,
        InitializingBean,
        DisposableBean {

    private String name;

    public ExampleBean() {
        System.out.println("1. Bean 实例化 - 构造函数执行");
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("2. 属性赋值 - 设置属性值: " + name);
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("3. BeanNameAware - Bean 名称: " + name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("4. BeanFactoryAware - 设置 BeanFactory");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("5. ApplicationContextAware - 设置 ApplicationContext");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("7. @PostConstruct - 初始化方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("8. InitializingBean.afterPropertiesSet - 属性设置完成后");
    }

    public void customInit() {
        System.out.println("9. 自定义 init 方法 - @Bean(initMethod)");
    }

    public void doSomething() {
        System.out.println("11. Bean 使用中 - 业务方法执行");
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("12. @PreDestroy - 销毁前方法");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("13. DisposableBean.destroy - 销毁方法");
    }

    public void customDestroy() {
        System.out.println("14. 自定义 destroy 方法 - @Bean(destroyMethod)");
    }
}

3. BeanPostProcessor 实现

typescript 复制代码
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ExampleBean) {
            System.out.println("6. BeanPostProcessor.postProcessBeforeInitialization - 初始化前处理");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ExampleBean) {
            System.out.println("10. BeanPostProcessor.postProcessAfterInitialization - 初始化后处理");
        }
        return bean;
    }
}

4. 测试类

arduino 复制代码
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class LifecycleTest {
    public static void main(String[] args) {
        System.out.println("=== Spring Bean 生命周期演示 ===");
        
        AnnotationConfigApplicationContext context = 
            new AnnotationConfigApplicationContext(AppConfig.class);
        
        ExampleBean exampleBean = context.getBean(ExampleBean.class);
        exampleBean.doSomething();
        
        System.out.println("=== 关闭 Spring 容器 ===");
        context.close();
    }
}

输出结果

markdown 复制代码
=== Spring Bean 生命周期演示 ===
1. Bean 实例化 - 构造函数执行
2. 属性赋值 - 设置属性值: null
3. BeanNameAware - Bean 名称: exampleBean
4. BeanFactoryAware - 设置 BeanFactory
5. ApplicationContextAware - 设置 ApplicationContext
6. BeanPostProcessor.postProcessBeforeInitialization - 初始化前处理
7. @PostConstruct - 初始化方法
8. InitializingBean.afterPropertiesSet - 属性设置完成后
9. 自定义 init 方法 - @Bean(initMethod)
10. BeanPostProcessor.postProcessAfterInitialization - 初始化后处理
11. Bean 使用中 - 业务方法执行
=== 关闭 Spring 容器 ===
12. @PreDestroy - 销毁前方法
13. DisposableBean.destroy - 销毁方法
14. 自定义 destroy 方法 - @Bean(destroyMethod)

初始化前是否可以跳过属性赋值?

答案是否定的。Spring 的设计理念是:

属性赋值必须在初始化阶段之前完成

原因如下:

  1. 初始化逻辑通常依赖 Bean 已经注入的属性。
  2. 如果初始化方法提前执行,未注入属性可能导致 NullPointerException 或状态不完整。
  3. Bean 的生命周期有严格顺序,确保每个阶段都能安全执行。

因此,即便在 @PostConstructInitializingBean.afterPropertiesSet 或自定义初始化方法中访问 Bean 属性,也可以放心使用,不会出现未赋值的情况。

相关推荐
爱勇宝6 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
AskHarries6 小时前
工具失败时怎么办:重试、回滚、人工确认和风险提示
后端·程序员
苏三说技术7 小时前
Claude Code从失控到起飞,只用了这些技巧
后端
长栎8 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode8 小时前
Redis 在生产项目的使用
前端·后端
用户559822481228 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode8 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战8 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha9 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn9 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端