Spring 中 Bean 的生命周期

在Spring框架中,"bean"这一术语特指那些受Inversion of Control (IoC) 容器管理的对象,它们通常都通过Dependency Injection (DI) 自动装配,无需开发者直接干预其生命周期管理。然而,在某些场景下,对特定 bean 进行定制化的初始化与销毁操作成为必要,此时就可以通过 Spring 中的拓展接口来实现。

基本生命周期#

Spring 中 IoC 的顶层接口是 BeanFactory,默认实现是 DefaultListableBeanFactory,我们可以在 BeanFactory 的注释文档中看到关于 bean 生命周期的介绍,其主要有以下几类:

初始化#

以下初始化方法都发生在属性注入之后

  1. 调用各种实现了 Spring 中自带的 Aware 接口中的方法

  2. 执行实现了 BeanPostProcessor 接口的 postProcessBeforeInitialization 方法

  3. 执行实现了 InitializingBean 接口的 afterPropertiesSet 方法

  4. 调用 bean 的 init-method

  5. 执行实现了 BeanPostProcessor 接口的 postProcessAfterInitialization 方法

销毁#

  1. 执行实现了 DestructionAwareBeanPostProcessor 接口的 postProcessBeforeDestruction 方法

  2. 执行实现了 DisposableBean 接口的 destroy 方法

  3. 调用 bean 的 destroy-method

bean 整体的生命周期阶段可以分为:实例化、属性填充、初始化、running 和销毁,相关的拓展主要在初始化和销毁阶段

实现原理#

Spring 会在 doCreateBean 过程中的 populateBean 方法之后执行 initializeBean 方法,该方法会按照 BeanFactory 文档中描述的顺序依次执行对应的生命周期钩子函数

  protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
      invokeAwareMethods(beanName, bean);

      Object wrappedBean = bean;
      if (mbd == null || !mbd.isSynthetic()) {
          wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
      }

      try {
          invokeInitMethods(beanName, wrappedBean, mbd);
      }
      catch (Throwable ex) {
          throw new BeanCreationException(
                  (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
      }
      if (mbd == null || !mbd.isSynthetic()) {
          wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
      }

      return wrappedBean;
  }

拓展生命周期#

在 Spring 中,除了 BeanFactory 中描述的钩子之外,还通过 CommonAnnotationBeanPostProcessor 提供了对 JSR-250 的 @PostConstruct and @PreDestroy 的支持 (是基于 BeanPostProcessor 接口实现的)

顺序总览#

因此,在 Spring 中的 createBean 阶段共提供了 4 对针对 bean 初始化和销毁的生命周期函数钩子,他们的执行顺序依次为:

  1. BeanPostProcessor#postProcessBeforeInitialization

  2. @PostConstruct

  3. InitializingBean#afterPropertiesSet

  4. init-method

  5. BeanPostProcessor#postProcessBeforeDestruction

  6. @PreDestroy

  7. DisposableBean#destroy

  8. destroy-method

区别#

  • BeanPostProcessor 可以实现对已经实例化的 bean 进行替换,而其他钩子函数无法修改 bean 的引用对象

  • @PostConstruct、@PreDestroy 组合的钩子函数可以实现应用与 Spring 的解耦

  • init-method、destroy-method 相较于 InitializingBean、DisposableBean 的组合可以实现业务代码与 Spring 的解耦,但是不常用

应用级生命周期#

以上所讲的生命周期钩子函数都是围绕单个 bean 的 createBean 阶段进行的,这个阶段通常在容器的单例创建锁中执行的。此阶段中的 bean 可能还未完全初始化,不应该在此阶段中调用外部 bean,因为存在初始化死锁或循环引用的风险。

@Configuration(proxyBeanMethods = false)
class CircularReference {
    @Component
    class C1(): BeanFactoryAware {
        override fun setBeanFactory(beanFactory: BeanFactory) {
            println(beanFactory.getBean(C1::class.java))
        }
    }

    @Component
    class C2(): BeanFactoryAware {
        override fun setBeanFactory(beanFactory: BeanFactory) {
            println(beanFactory.getBean(C1::class.java))
        }
    }
}

针对以上问题,可以通过应用级的生命周期钩子函数来解决,通常有以下几种方案:

  • 实现 SmartInitializingSingleton 接口

  • 实现 SmartLifecycle 接口

  • 监听 ContextRefreshedEvent 事件

调用时机#

  1. SmartInitializingSingleton 对应的钩子函数会在 Spring 应用 refresh 阶段中所有单例 bean 初始化完成后触发,适合执行那些依赖整个容器状态的操作。

  2. SmartLifecycle 对应的钩子函数会在 Spring 应用 refresh 阶段中的 finishRefresh 方法中调用。

  3. ContextRefreshedEvent 事件也会在 Spring 应用 refresh 阶段中的 finishRefresh 方法中发布。

Lifecycle 和 SmartLifecycle 的区别是:后者的钩子函数会在 Spring 应用的 refresh 阶段被自动调用,而前者需要手动调用 application 的 start 方法

总结#

Spring框架通过高度可定制的bean生命周期管理模型,赋予了开发者强大的控制能力,不仅能够精确地控制单个bean的行为,还能有效地管理整个应用的启动与关闭流程,是构建高质量、可维护的Java应用不可或缺的一部分。

作者:xtyuns

出处:https://www.cnblogs.com/xtyuns/p/18171453

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   xtyuns  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示