您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

Spring Bean 生命周期

时间:2023-08-29 14:17:49  来源:  作者:码哥字节

1.概述

首先Bean就是一些JAVA对象,只不过这些Bean不是我们主动new出来的,而是交个Spring IOC容器创建并管理的,因此Bean的生命周期受Spring IOC容器控制,Bean生命周期大致分为以下几个阶段:

  • Bean的实例化(Instantiation):Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton的,是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化

  • Bean的属性赋值(Populate):Bean实例化之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充,Bean的属性赋值就是指 Spring 容器根据BeanDefinition中属性配置的属性值注入到 Bean 对象中的过程。

  • Bean的初始化(Initialization):对Bean实例的属性进行填充完之后还需要执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段,并且Spring高频面试题Bean的循环引用问题也是在这个阶段体现的;

  • Bean的使用阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期,接下来Bean就可以被随心所欲地使用了。

  • Bean的销毁(Destruction):Bean 的销毁是指 Spring 容器在关闭时,执行一些清理操作的过程。在 Spring 容器中, Bean 的销毁方式有两种:销毁方法destroy-method和 DisposableBean 接口。

2.Bean生命周期详解和使用案例

BeanDefinitionRegistryPostProcessor,BeanFactoryPostProcessor,BeanPostProcessor这三个后置处理器的调用时机都在Spring Bean生命周期中是不严谨的,按照上面我们对Bean生命周期的阶段划分,只有BeanPostProcessor作用于Bean的生命周期中,而BeanDefinitionRegistryPostProcessor,BeanFactoryPostProcessor是针对BeanDefinition的,所以不属于Bean的生命周期中。

BeanPostProcessor在Bean生命周期的体现如下图所示:

Bean的生命周期和人的一生一样都会经历从出生到死亡,中间是一个漫长且复杂的过程,接下来我们就来整体分析一下Bean生命周期的核心流程和相关接口回调方法的调用时机,同时这里想强调一下Bean的生命周期也是面试的高频考点,对核心流程务必要掌握清楚,这里用一张流程图进行详述展示,是重点、重点、重点

根据上面的Bean生命周期核心流程做如下代码演示示例:

Bean定义:

@Data
@AllArgsConstructor
public class Boo implements InitializingBean, DisposableBean, BeanNameAware {
    private Long id;
    private String name;

    public Boo() {
        System.out.println("boo实例化构造方法执行了...");
    }

    @PostConstruct
    public void initMethod() {
        System.out.println("boo执行初始化init()方法了...");
    }

    @PreDestroy
    public void destroyMethod() {
        System.out.println("boo执行初始化destroy()方法了...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("boo执行InitializingBean的afterPropertiesSet()方法了...");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("boo执行DisposableBean的destroy()方法了...");
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("boo执行BeanNameAware的setBeanName()方法了...");
    }
}

实现InstantiationAwareBeanPostProcessor:

@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> BeanClass, String BeanName) throws BeansException {
        System.out.println("InstantiationAwareBeanPostProcessor的before()执行了...." + BeanName);
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object Bean, String BeanName) throws BeansException {
        System.out.println("InstantiationAwareBeanPostProcessor的after()执行了...." + BeanName);
        return false;
    }
}

实现BeanPostProcessor:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object Bean, String BeanName) throws BeansException {
        System.out.println("BeanPostProcessor的before()执行了...." + BeanName);
        return Bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object Bean, String BeanName) throws BeansException {
        System.out.println("BeanPostProcessor的after()执行了...."+ BeanName);
        return Bean;
    }
}

执行下面的配置类测试方法:

@ComponentScan(basePackages = {"com.shepherd.common.config"})
@Configuration
public class MyConfig {

    @Bean
    public Boo boo() {
        return new Boo();
    }

    public static void mAIn(String[] args) {

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        String[] BeanDefinitionNames = applicationContext.getBeanDefinitionNames();
        // 遍历Spring容器中的BeanName
        for (String BeanDefinitionName : BeanDefinitionNames) {
            System.out.println(BeanDefinitionName);
        }
        // 这里调用的applicationContext的close()触发Bean的销毁回调方法
        applicationContext.close();
    }
}

名为boo的Bean相关运行结果如下:

InstantiationAwareBeanPostProcessor的before()执行了....boo
boo实例化构造方法执行了...
InstantiationAwareBeanPostProcessor的after()执行了....boo
boo执行BeanNameAware的setBeanName()方法了...
BeanPostProcessor的before()执行了....boo
boo执行初始化init()方法了...
boo执行InitializingBean的afterPropertiesSet()方法了...
BeanPostProcessor的after()执行了....boo
......
boo执行初始化destroy()方法了...
boo执行DisposableBean的destroy()方法了...

根据控制台打印结果可以boo的相关方法执行顺序严格遵从上面流程图,同时当我们执行容器applicationContext的关闭方法close()会触发调用bean的销毁回调方法。

3.浅析Bean生命周期源码实现

DefaultListableBeanFactory是Spring IOC的Bean工厂的一个默认实现,IOC大部分核心逻辑实现都在这里,可关注。Bean生命周期就是创建Bean的过程,这里我们就不在拐弯抹角兜圈子,直接来到DefaultListableBeanFactory继承的AbstractAutowireCapableBeanFactory#doCreateBean()方法,之前说过在Spring框架中以do开头的方法都是核心逻辑实现所在

protected Object doCreateBean(String BeanName, RootBeanDefinition mbd, @Nullable Object[] args)
   throws BeanCreationException {

  // Instantiate the Bean.
  // BeanWrapper 是对 Bean 的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装 Bean 的属性描述器
  BeanWrapper instanceWrapper = null;
  if (mbd.isSingleton()) {
   // <1> 单例模型,则从未完成的 FactoryBean 缓存中删除
   instanceWrapper = this.factoryBeanInstanceCache.remove(BeanName);
  }
  if (instanceWrapper == null) {
   // <2> 使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化
   instanceWrapper = createBeanInstance(BeanName, mbd, args);
  }
  // 包装的实例对象
  Object Bean = instanceWrapper.getWrappedInstance();
  // 包装的实例class类型
  Class<?> BeanType = instanceWrapper.getWrappedClass();
  if (BeanType != NullBean.class) {
   mbd.resolvedTargetType = BeanType;
  }

  // Allow post-processors to modify the merged Bean definition.
  // <3> 判断是否有后置处理
  // 如果有后置处理,则允许后置处理修改 BeanDefinition
  synchronized (mbd.postProcessingLock) {
   if (!mbd.postProcessed) {
    try {
     applyMergedBeanDefinitionPostProcessors(mbd, BeanType, BeanName);
    }
    catch (Throwable ex) {
     throw new BeanCreationException(mbd.getResourceDescription(), BeanName,
       "Post-processing of merged Bean definition failed", ex);
    }
    mbd.postProcessed = true;
   }
  }

  // Eagerly cache singletons to be able to resolve circular references
  // even when triggered by lifecycle interfaces like BeanFactoryAware.
  // <4> 解决单例模式的循环依赖
  boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
    isSingletonCurrentlyInCreation(BeanName));
  if (earlySingletonExposure) {
   if (logger.isTraceEnabled()) {
    logger.trace("Eagerly caching Bean '" + BeanName +
      "' to allow for resolving potential circular references");
   }
   // 提前将创建的 Bean 实例加入到 singletonFactories 中
   // 这里是为了后期避免循环依赖
   addSingletonFactory(BeanName, () -> getEarlyBeanReference(BeanName, mbd, Bean));
  }

  // Initialize the Bean instance.
  // 开始初始化 Bean 实例对象
  Object exposedObject = Bean;
  try {
   // <5> 对 Bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 Bean 的属性
   // 则会递归初始依赖 Bean
   populateBean(BeanName, mbd, instanceWrapper);
   // <6> 调用初始化方法
   exposedObject = initializeBean(BeanName, exposedObject, mbd);
  }
  catch (Throwable ex) {
   if (ex instanceof BeanCreationException && BeanName.equals(((BeanCreationException) ex).getBeanName())) {
    throw (BeanCreationException) ex;
   }
   else {
    throw new BeanCreationException(
      mbd.getResourceDescription(), BeanName, "Initialization of Bean failed", ex);
   }
  }

  // <7> 循环依赖处理
  if (earlySingletonExposure) {
   // 获取 earlySingletonReference
   Object earlySingletonReference = getSingleton(BeanName, false);
   // 只有在存在循环依赖的情况下,earlySingletonReference 才不会为空
   if (earlySingletonReference != null) {
    // 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强
    if (exposedObject == Bean) {
     exposedObject = earlySingletonReference;
    }
    // 处理依赖
    else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(BeanName)) {
     String[] dependentBeans = getDependentBeans(BeanName);
     Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
     for (String dependentBean : dependentBeans) {
      if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
       actualDependentBeans.add(dependentBean);
      }
     }
     if (!actualDependentBeans.isEmpty()) {
      throw new BeanCurrentlyInCreationException(BeanName,
        "Bean with name '" + BeanName + "' has been injected into other Beans [" +
        StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
        "] in its raw version as part of a circular reference, but has eventually been " +
        "wrapped. This means that said other Beans do not use the final version of the " +
        "Bean. This is often the result of over-eager type matching - consider using " +
        "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
     }
    }
   }
  }

  // Register Bean as disposable.
  try {
   // <8> 注册 Bean的销毁逻辑
   registerDisposableBeanIfNecessary(BeanName, Bean, mbd);
  }
  catch (BeanDefinitionValidationException ex) {
   throw new BeanCreationException(
     mbd.getResourceDescription(), BeanName, "Invalid destruction signature", ex);
  }

  return exposedObject;
 }

由上面代码可知,Bean的创建过程核心步骤如下:

  • createBeanInstance(BeanName, mbd, args) 进行Bean的实例化
  • populateBean(BeanName, mbd, instanceWrapper)进行Bean的属性填充赋值
  • initializeBean(BeanName, exposedObject, mbd)处理Bean初始化之后的各种回调事件
  • registerDisposableBeanIfNecessary(BeanName, Bean, mbd)注册Bean的销毁接口
  • 解决创建Bean过程中的循环依赖,Spring使用三级缓存解决循环依赖,这也是一个重要的知识点,这里不详细阐述,后面会安排

接下来我们就来看看和Bean初始化阶段相关各种回调事件执行方法#initializeBean(),分析一下上面流程图的执行顺序是怎么实现的。

protected Object initializeBean(final String BeanName, final Object Bean, RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    invokeAwareMethods(BeanName, Bean);
                    return null;
                }
            }, getAccessControlContext());
        }
        else {
            // 涉及到的回调接口点进去一目了然,代码都是自解释的
            // BeanNameAware、BeanClassLoaderAware或BeanFactoryAware
            invokeAwareMethods(BeanName, Bean);
        }

        Object wrappedBean = Bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // BeanPostProcessor 的 postProcessBeforeInitialization 回调
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, BeanName);
        }

        try {
            // init-methods
            // 或者是实现了InitializingBean接口,会调用afterPropertiesSet() 方法
            invokeInitMethods(BeanName, wrappedBean, mbd);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    (mbd != null ? mbd.getResourceDescription() : null),
                    BeanName, "Invocation of init method failed", ex);
        }
        if (mbd == null || !mbd.isSynthetic()) {
            // BeanPostProcessor 的 postProcessAfterInitialization 回调
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, BeanName);
        }
        return wrappedBean;
    }

至于Bean的销毁流程与Bean初始化类似,从上面的使用示例中看可以得出当容器关闭时,才会对Bean销毁方法进行调用。销毁过程是这样的。顺着close()-> doClose() -> destroyBeans() -> destroySingletons() -> destroySingleton() -> destroyBean() -> Bean.destroy() ,会看到最终调用Bean的销毁方法。这里就不在展示源码细节啦,有兴趣的话自行去调试查看了解

4.总结

以上全部就是对Spring Bean生命周期的全面总结, Spring 的 Bean 容器机制是非常强大的,它可以帮助我们轻松地管理 Bean 对象,并且提供了丰富的生命周期回调方法,允许我们在 Bean 的生命周期中执行自己的特定操作,这对于我们平时工作使用中进行增强扩展至关重要,因此掌握Bean的生命周期是必须的。



Tags:Spring   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Spring Security:保障应用安全的利器
SpringSecurity作为一个功能强大的安全框架,为Java应用程序提供了全面的安全保障,包括认证、授权、防护和集成等方面。本文将介绍SpringSecurity在这些方面的特性和优势,以及它...【详细内容】
2024-02-27  Search: Spring  点击:(52)  评论:(0)  加入收藏
Spring Security权限控制框架使用指南
在常用的后台管理系统中,通常都会有访问权限控制的需求,用于限制不同人员对于接口的访问能力,如果用户不具备指定的权限,则不能访问某些接口。本文将用 waynboot-mall 项目举例...【详细内容】
2024-02-19  Search: Spring  点击:(39)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  Search: Spring  点击:(10)  评论:(0)  加入收藏
Spring实现Kafka重试Topic,真的太香了
概述Kafka的强大功能之一是每个分区都有一个Consumer的偏移值。该偏移值是消费者将读取的下一条消息的值。可以自动或手动增加该值。如果我们由于错误而无法处理消息并想重...【详细内容】
2024-01-26  Search: Spring  点击:(84)  评论:(0)  加入收藏
SpringBoot如何实现缓存预热?
缓存预热是指在 Spring Boot 项目启动时,预先将数据加载到缓存系统(如 Redis)中的一种机制。那么问题来了,在 Spring Boot 项目启动之后,在什么时候?在哪里可以将数据加载到缓存系...【详细内容】
2024-01-19  Search: Spring  点击:(86)  评论:(0)  加入收藏
Spring Boot2.0深度实践 核心原理拆解+源码分析
Spring Boot2.0深度实践:核心原理拆解与源码分析一、引言Spring Boot是一个基于Java的轻量级框架,它简化了Spring应用程序的创建过程,使得开发者能够快速搭建一个可运行的应用...【详细内容】
2024-01-15  Search: Spring  点击:(93)  评论:(0)  加入收藏
SpringBoot3+Vue3 开发高并发秒杀抢购系统
开发高并发秒杀抢购系统:使用SpringBoot3+Vue3的实践之旅随着互联网技术的发展,电商行业对秒杀抢购系统的需求越来越高。为了满足这种高并发、高流量的场景,我们决定使用Spring...【详细内容】
2024-01-14  Search: Spring  点击:(90)  评论:(0)  加入收藏
Spring Boot 3.0是什么?
Spring Boot 3.0是一款基于Java的开源框架,用于简化Spring应用程序的构建和开发过程。与之前的版本相比,Spring Boot 3.0在多个方面进行了改进和增强,使其更加易用、高效和灵活...【详细内容】
2024-01-11  Search: Spring  点击:(132)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11  Search: Spring  点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  Search: Spring  点击:(115)  评论:(0)  加入收藏
▌简易百科推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  步步运维步步坑    Tags:架构   点击:(5)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27    InfoQ  Tags:架构模式   点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  哈啰技术  微信公众号  Tags:架构   点击:(10)  评论:(0)  加入收藏
DDD 与 CQRS 才是黄金组合
在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能扛...【详细内容】
2024-03-27  dbaplus社群    Tags:DDD   点击:(11)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13    阿里云开发者  Tags:高并发   点击:(6)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  二进制跳动  微信公众号  Tags:架构设计   点击:(36)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  ijunfu  今日头条  Tags:SpringBoot   点击:(10)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  547蓝色星球    Tags:架构   点击:(115)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11    王建立  Tags:Spring Boot   点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  互联网架构小马哥    Tags:Spring Boot   点击:(115)  评论:(0)  加入收藏
站内最新
站内热门
站内头条