SpringBean的初始化流程

2023-10-14 19:52
文章标签 流程 初始化 springbean

本文主要是介绍SpringBean的初始化流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 当我们启动Spring容器后,会先通过AbstractApplicationContext#refresh方法,调用BeanFactoryPostProcess方法,可以在bean初始化前,修改context中的BeanDefinition,但是因为此时Bean还没有初始化,所以并不会修改bean实例,如下代码所示:

  • 然后会开始初始化非懒加载的bean,具体分为以下几步:
  • 1. 通过 InstantiationAwareBeanPostProcessor 在实例化bean之前做前置处理
  • 2. 通过反射实例化该bean(有多种情况,分为有参数,无参数构造器,以及是否有Autowired注解)
  • 3. 填充Bean的field实例(此时可能会有循环依赖问题,涉及到循环初始化)
  • 4. 调用初始化方法之前,先调用 BeanPostProcessor #postProcessBeforeInitialization 方法(各种Aware的织入就在此处执行)
  • 5. 执行该bean的初始化方法,如 InitializingBean #afterProperties 方法,或者自定义的init-method方法
  • 6. 调用 BeanPostProcessor #postProcessAfterInitialization 执行初始化的后置处理方法
  • 7. 如果该bean有相关的销毁方法,则将对应的销毁方法注册进容器中,当销毁bean的时候会进行回调处理
  • 源码如下所示:

  • 整体过程如下图所示:

  • 如果两个bean互相依赖,该如何初始化
    • Spring Bean的循环依赖问题_兔子队列的博客-CSDN博客
  • SpringBean的生命周期
    • 在传统的Java应用中,bean的生命周期很简单
      • 使用Java关键字new进行bean实例化,然后该bean就可以使用了
      • 一旦该bean不再被使用,则由Java自动进行垃圾回收
    • 相比之下,Spring容器中的bean的生命周期就显得相对复杂多了
    • 正确理解Spring bean的生命周期非常重要,因为你或许要利用Spring提供的扩展点来自定义bean的创建过程
    • Singleton生命周期完全由容器控制,Singleton是如下所述,prototype类型的Bean完成实例化之后就由调用方去管理后续流程了,IoC容器不再管理
    • 下图展示了bean装载到Spring应用上下文中的一个典型的生命周期过程

    • bean在Spring容器中从创建到销毁经历了若干阶段,每一阶段都可以针对Spring如何管理bean进行个性化定制
    • 正如你所见,在bean准备就绪之前,bean工厂执行了若干启动步骤
    • 我们对上图进行详细描述:

      • 1-实例化
        • Spring对bean进行实例化;实例化一个Bean,也就是我们常说的new
        • 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化
        • 对于ApplicationContext容器,当容器启动结束后,便实例化所有的bean
        • 容器通过获取BeanDefinition对象中的信息进行实例化
        • 并且这一步仅仅是简单的实例化,并未进行依赖注入
        • 实例化对象被包装在BeanWrapper对象中,BeanWrapper提供了设置对象属性的接口,从而避免了使用反射机制设置属性
      • 2-IOC依赖注入
        • Spring将值和bean的引用注入到bean对应的属性中;按照 Spring 上下文对实例化的 Bean 进行配置,也就是 IOC 注入
        • 实例化后的对象被封装在BeanWrapper对象中,并且此时对象仍然是一个原生的状态,并没有进行依赖注入
        • 紧接着,Spring根据BeanDefinition中的信息进行依赖注入
        • 并且通过BeanWrapper提供的设置属性的接口完成依赖注入
      • 3,4,5-注入Aware接口
        • 紧接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给bean(BeanNameAware,BeanFactoryAware,ApplicationContextAware)
      • 3-setBeanName实现
        • 如果bean实现了BeanNameAware接口,会调用它实现的 setBeanName(String) 方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值
      • 4-BeanFactoryAware实现
        • 如果bean实现了BeanFactoryAware接口,会调用它实现的 setBeanFactory,setBeanFactory(BeanFactory)传递的是 Spring 工厂自身(可以用这个方式来获取其它Bean,只需在 Spring 配置文件中配置一个普通的 Bean 就可以)
      • 5-ApplicationContextAware实现
        • 如果bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入 Spring 上下文(同样这个方式也可以实现步骤 4 的内容,但比 4 更好,因为 ApplicationContext 是 BeanFactory 的子接口,有更多的实现方法)
      • 6,8-BeanPostProcessor
        • 当经过上述几个步骤后,bean对象已经被正确构造,但如果你想要对象被使用前再进行一些自定义的处理,就可以通过BeanPostProcessor接口实现
        • 作用是在Bean实例创建成功后对其进行增强处理,如对Bean进行修改,增加某个功能
        • 该接口提供了两个函数:
          • postProcessBeforeInitialzation( Object bean, String beanName )
            • 当前正在初始化的bean对象会被传递进来,我们就可以对这个bean做任何处理
            • 这个函数会先于InitialzationBean执行,因此称为前置处理
            • 所有Aware接口的注入就是在这一步完成的
          • postProcessAfterInitialzation( Object bean, String beanName )
            • 这个函数会在InitialzationBean完成后执行,因此称为后置处理
      • 6-postProcessBeforeInitialization接口实现-初始化预处理
        • 如果bean实现了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor 经常被用作是 Bean 内容的更改,并且由于这个是在 Bean 初始化结束时调用那个的方法,也可以被应用于内存或缓存技术
      • 7-InitializingBean与init-method
        • 如果bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()方法
        • 类似地,如果 Bean 在 Spring 配置文件中配置了 init-method 属性会自动调用其配置的初始化方法
        • 如果Bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet方法,作用与在配置文件中对Bean使用init-method声明初始化的作用一样,都是在Bean的全部属性设置成功后执行的初始化方法
        • 若要使用它,我们需要让bean实现该接口,并把要增加的逻辑写在该函数中
        • 然后Spring会在前置处理完成后检测当前bean是否实现了该接口,并执行afterPropertiesSet函数
        • 当然,Spring为了降低对客户代码的侵入性,给bean的配置提供了init-method属性,该属性指定了在这一阶段需要执行的函数名
        • Spring便会在初始化阶段执行我们设置的函数
        • init-method本质上仍然使用了InitializingBean接口
      • 8-postProcessAfterInitialization
        • 如果bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法
      • 注:以上工作完成以后就可以应用这个 Bean 了,那这个 Bean 是一个 Singleton 的,所以一般情况下我们调用同一个 id 的 Bean 会是在内容地址相同的实例,当然在 Spring 配置文件中也可以配置非 Singleton
      • 此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁
      • 9-Destroy 过期自动清理阶段
        • 当 Bean 不再需要时,会经过清理阶段,如果bean实现了DisposableBean接口,会调用那个其实现的 destroy() 方法
      • 10-destroy-method 自配置清理
        • 最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法
      • 现在你已经了解了如何创建和加载一个Spring容器
      • 但是一个空的容器并没有太大的价值,在你把东西放进去之前,它里面什么都没有
      • 为了从Spring的DI(依赖注入)中受益,我们必须将应用对象装配进Spring容器中
    • 有两个重要的 bean 生命周期方法,第一个是setup,它是在容器加载bean的时候被调用
    • 第二个方法是 teardown 它是在容器卸载类的时候被调用
    • bean 标签有两个重要的属性(init-method和destroy-method)
    • 用它们你可以自己定制初始化和注销方法;它们也有相应的注解(@PostConstruct和@PreDestroy)

这篇关于SpringBean的初始化流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/212772

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

c++的初始化列表与const成员

初始化列表与const成员 const成员 使用const修饰的类、结构、联合的成员变量,在类对象创建完成前一定要初始化。 不能在构造函数中初始化const成员,因为执行构造函数时,类对象已经创建完成,只有类对象创建完成才能调用成员函数,构造函数虽然特殊但也是成员函数。 在定义const成员时进行初始化,该语法只有在C11语法标准下才支持。 初始化列表 在构造函数小括号后面,主要用于给

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

火语言RPA流程组件介绍--浏览网页

🚩【组件功能】:浏览器打开指定网址或本地html文件 配置预览 配置说明 网址URL 支持T或# 默认FLOW输入项 输入需要打开的网址URL 超时时间 支持T或# 打开网页超时时间 执行后后等待时间(ms) 支持T或# 当前组件执行完成后继续等待的时间 UserAgent 支持T或# User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器

UMI复现代码运行逻辑全流程(一)——eval_real.py(尚在更新)

一、文件夹功能解析 全文件夹如下 其中,核心文件作用为: diffusion_policy:扩散策略核心文件夹,包含了众多模型及基础库 example:标定及配置文件 scripts/scripts_real:测试脚本文件,区别在于前者倾向于单体运行,后者为整体运行 scripts_slam_pipeline:orb_slam3运行全部文件 umi:核心交互文件夹,作用在于构建真

C++/《C/C++程序编译流程》

程序的基本流程如图:   1.预处理        预处理相当于根据预处理指令组装新的C/C++程序。经过预处理,会产生一个没有宏定义,没有条件编译指令,没有特殊符号的输出文件,这个文件的含义同原本的文件无异,只是内容上有所不同。 读取C/C++源程序,对其中的伪指令(以#开头的指令)进行处理将所有的“#define”删除,并且展开所有的宏定义处理所有的条件编译指令,如:“#if”、“

笔记本电脑的具体选购步骤流程

2.1 笔记本电脑的具体选购步骤流程   关于笔记本电脑的选购,一直是热点话题。不管是新手还是老前辈,选购前,总是要先上网查一查,汇总一些信息或经验。因为选购一台笔记本电脑,从它的配置、外观到做工等很多方面都需要考量,所以挑一台自己喜欢的、适合自己的笔记本电脑也是一件很费脑筋的事情。本节将一些选购笔记本电脑的经验进行了总结,供广大读者选购笔记本电脑时参考。   笔记本电脑选购流程如下