Spring Bean 的生命周期是怎么样的?

一则或许对你有用的小广告

欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于 Spring AI + Spring Boot3.x + JDK 21...点击查看;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot3.x + JDK 17...点击查看项目介绍; 演示链接: http://116.62.199.48:7070/;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/

面试考察点

面试官抛出这个问题,通常想考察以下几个层面的理解:

  1. 对 Spring IoC 容器核心机制的理解深度:不仅要知道步骤,更要明白每个步骤存在的意义和底层原理。
  2. 实际应用与扩展能力:能否在生命周期中的正确节点(如 InitializingBean@PostConstructBeanPostProcessor)进行自定义逻辑注入,解决实际问题。
  3. 知识体系的完整性:能否清晰地区分 BeanFactoryApplicationContext 在生命周期处理上的细微差别,以及不同作用域(如 singletonprototype)生命周期的不同。
  4. 问题排查与设计能力:当 Bean 的创建、依赖注入或销毁出现问题时,是否能根据生命周期流程快速定位。

核心答案

Spring Bean 的生命周期指的是一个 Bean 在 Spring IoC 容器中从被实例化、装配属性、初始化到最终被销毁的完整过程。其核心流程可以概括为四个大阶段和一系列扩展点:

  1. 实例化:容器通过反射(如构造器)或工厂方法创建 Bean 的实例。
  2. 属性赋值:为 Bean 注入依赖的属性(通过 setter、字段或构造器),并处理 Aware 接口回调。
  3. 初始化:执行各种初始化回调,使 Bean 达到可用状态。
  4. 销毁:在容器关闭时,执行预定义的销毁逻辑。

深度解析

原理/机制详解

1. 实例化与属性赋值

  • 实例化:容器根据 Bean 定义(BeanDefinition)选择合适的策略(如 CglibSubclassingInstantiationStrategy)创建对象。此时对象只是一个 “空壳”,属性均为默认值。
  • 属性赋值:此阶段核心是 依赖注入(DI)。容器解析 @Autowired@Value<property> 等元数据,完成属性填充。Aware 接口回调也发生在此阶段之后,目的是让 Bean 能感知到容器自身的一些基础设施对象(如 BeanNameAwareBeanFactoryAwareApplicationContextAware)。

2. 初始化——生命周期中的 “精加工” 这是最复杂且扩展性最强的阶段,包含多个有序的扩展点:

  • BeanPostProcessor 初始化前BeanPostProcessor 是 Spring 提供的强大扩展接口。postProcessBeforeInitialization 方法允许在 Bean 的任何自定义初始化方法被调用之前,对 Bean 进行修改或包装(例如, @Autowired 注解的处理就是通过 AutowiredAnnotationBeanPostProcessor 完成的)。
  • 自定义初始化:按顺序执行:
    1. @PostConstruct 注解标注的方法(JSR-250 标准)。
    2. InitializingBean 接口的 afterPropertiesSet() 方法。
    3. 通过 XML 的 init-method 属性或 @Bean(initMethod = “…”) 指定的方法。
  • BeanPostProcessor 初始化后:在自定义初始化方法执行之后调用。这是 AOP 代理创建的关键时机AbstractAutoProxyCreator 等后置处理器会在此检查 Bean,如果需要被代理,则会返回一个代理对象,而不是原始 Bean。这也是为什么注入的 Bean 通常已经是代理对象的原因。

3. 销毁 与初始化对应,销毁阶段也有类似的回调顺序(仅对 singleton Bean 有效,prototype Bean 容器不管理其销毁):

  1. @PreDestroy 注解标注的方法。
  2. DisposableBean 接口的 destroy() 方法。
  3. 通过 XML 的 destroy-method 属性或 @Bean(destroyMethod = “…”) 指定的方法。

代码示例

@Component
public class LifecycleDemoBean implements BeanNameAware, InitializingBean, DisposableBean {
    private String beanName;

    public LifecycleDemoBean() {
        System.out.println("1. 构造器调用 -> 实例化");
    }

    @Autowired
    public void setDependency(SomeService service) {
        System.out.println("2. 依赖注入 (Autowired)");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("3. Aware接口回调 (BeanNameAware)");
    }

    @PostConstruct
    public void postConstruct() {
        System.out.println("5. @PostConstruct 方法");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("6. InitializingBean.afterPropertiesSet()");
    }

    public void customInit() {
        System.out.println("7. 自定义 init-method");
    }

    @Override
    @PreDestroy
    public void destroy() {
        System.out.println("9. @PreDestroy 方法(与DisposableBean.destroy()合并)");
    }

    public void customDestroy() {
        System.out.println("10. 自定义 destroy-method");
    }
}

// 定义一个 BeanPostProcessor
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if (bean instanceof LifecycleDemoBean) {
            System.out.println("4. BeanPostProcessor.postProcessBeforeInitialization");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof LifecycleDemoBean) {
            System.out.println("8. BeanPostProcessor.postProcessAfterInitialization (AOP代理通常在此生成)");
        }
        return bean;
    }
}

最佳实践与注意事项

  • 推荐使用顺序:对于初始化,建议优先使用 @PostConstruct(标准,与框架解耦),其次是 @BeaninitMethod,最后才是 InitializingBean 接口(将代码与 Spring 紧耦合)。销毁同理。
  • 理解作用域影响singleton Bean 会完整经历所有生命周期。prototype Bean 在容器只负责实例化、装配和初始化(到 postProcessAfterInitialization 为止),之后便将对象交给调用者,容器不再跟踪其生命周期,不会调用销毁方法
  • BeanPostProcessor 的威力与陷阱:它是全局性的,会应用到容器中所有 Bean,实现时务必通过 bean 的类型或 beanName 进行精确判断,避免无谓的性能开销和副作用。

常见误区

  • 混淆“实例化”和“初始化”:认为 new 出来的对象就是 Bean 了。实际上,未经过属性注入和初始化的对象,其功能是不完整的。
  • 认为 AOP 代理在初始化后单独进行:AOP 代理其实是某个特定的 BeanPostProcessor(如 AnnotationAwareAspectJAutoProxyCreator)在 postProcessAfterInitialization 阶段创建的,它是初始化流程的一部分。
  • 忽略 ApplicationContextBeanFactory 的区别ApplicationContext 在容器启动时就会预先实例化所有非懒加载的单例 Bean,而基础的 BeanFactory 默认是延迟初始化的。

总结

Spring Bean 的生命周期是一个由 IoC 容器驱动、通过定义良好的步骤和丰富的扩展点构建的精密流程,其核心目标是实现控制反转依赖注入,并通过 BeanPostProcessor 等机制提供了无与伦比的扩展灵活性。理解它,是编写高质量 Spring 应用和进行深度定制的基石。