深入理解 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 的生命周期有严格顺序,确保每个阶段都能安全执行。

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

相关推荐
java_nnnn20 分钟前
Spring MVC小案例(1)
java·后端·spring·mvc
陈随易26 分钟前
从今天起,你只需要一个浏览器之Ego lite
前端·后端·程序员
打工仔折腾 AI1 小时前
AI Agent 工程化实战(二):5 分钟跑通 Deep Agent 并逐层拆解底层链路
java·数据库·人工智能·后端·python·langchain·ai agent 实战
学长毕设1 小时前
基于springboot的农资管理系统-附源码
java·spring boot·后端
拖孩2 小时前
一个人 + AI 做的小程序,今天,正式回本了
前端·后端·微信小程序
进击的丸子2 小时前
代理网络环境下 Linux Pro 在线激活实操指南
javascript·后端·安全
念何架构之路3 小时前
Go reflect包值操作 Value 的读写、可设置性与 interface 布局
开发语言·后端·golang
小林ixn3 小时前
用 FastAPI + SQLAlchemy 从零手搓一个博客系统:一套能落地、能讲清楚的 RESTful 后端
后端·python·fastapi
不识君4 小时前
esl-client 2.0.0 发布:Java 项目接入 FreeSWITCH,从引入到使用
spring boot·后端·开源
牧瀬クリスだ4 小时前
Redis五大数据类型全解析:从入门到实战
java·数据库·redis·后端·缓存