SpringBean的初始化流程

news2024/10/6 18:25:08
  • 当我们启动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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1092188.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

valarray 包含对象成员的类(cpp14章)

C代码重用 1.公有继承可以实现 2.包含、私有继承、保护继承用于实现has-a关系,即新的类将包含另一个类的对象。 (使用这样类成员:本身是另外一个类对象称为包含 (组合或层次化)。) 3.函数模板、类模…

使用匿名函数在Golang中的好处

发挥Golang中无名代码块的潜力 匿名函数,也被称为lambda函数或闭包,是Golang中的一个强大功能,提供了许多好处。这些无名代码块为开发人员在设计和构建其代码时提供了更大的灵活性和模块化。在本节中,我们将探讨使用匿名函数可以…

访问控制列表ACL讲解——想偷偷访问数据,我ACL可不同意

作者:Insist-- 个人主页:insist--个人主页 梦想从未散场,传奇永不落幕,博主会持续更新优质网络知识、Python知识、Linux知识以及各种小技巧,愿你我共同在CSDN进步 目录 一、ACL的基本概念 1. ACL是什么 2. 为什么需…

Jenkins+Gitlab+Docker(Dockerfile)部署

Docker部署运行 ​ 上一篇内容中使用Jenkins(运行服务器)Gitlab(代码存储库)Webhook(网络钩子)的方式部署运行我们的项目。需要我们在服务器上做好很多相关的环境配置及依赖。 ​ 那么假如有这样一个场景:需要把不同技术栈的项目部署到同一台服务器上运行。比如PH…

DocCMS keyword SQL注入

漏洞描述 DocCMS keyword参数存在 SQL注入漏洞,攻击者通过漏洞可以获取数据库信息 漏洞复现 访问url: 漏洞证明: 文笔生疏,措辞浅薄,望各位大佬不吝赐教,万分感谢。 免责声明:由于传播或利…

400电话的技术实现要点

摘要:本文将介绍400电话的技术实现要点。首先,我们将讨论400电话的基本原理和技术架构。然后,我们将深入探讨400电话的关键技术,包括呼叫路由、语音导航、呼叫转接等。最后,我们将讨论如何保障400电话的稳定性和安全性…

JUnit5 【最实用最简洁】

JUnit5 文章目录 JUnit5一、JUnit 的相关技术二、参数化三、给测试用例指定顺序四、断言五、测试套件 安装依赖:在Maven库中安装 为什么学了 Selenium 还要学 JUnit? 1、JUnit5 是单元测试框架,拿着一个技术写自动化测试用例(Sele…

云上攻防-云原生篇Docker安全系统内核版本漏洞CDK自动利用容器逃逸

文章目录 云原生-Docker安全-容器逃逸&内核漏洞云原生-Docker安全-容器逃逸&版本漏洞-CVE-2019-5736 runC容器逃逸-CVE-2020-15257 containerd逃逸 云原生-Docker安全-容器逃逸&CDK自动化 云原生-Docker安全-容器逃逸&内核漏洞 细节部分在权限提升章节会详解&…

【肌电信号】OpenSignals使用方法 --- 肌电信号采集及导入matlab

一、 多通道采集教学 1. 数据线连接 将PLUX设备通过USB或蓝牙与电脑连接,注意确认在几号通道接线。 2.实时数据采集可视化 进行设置。需要在软件中选择你的PLUX设备,并配置相关的参数,如采样率、分辨率、信号类型等 3 支持数据回放和…

zabbix监控实战2

4、zabbix添加监控项 nginx监控 在server上安装nginx 添加模板 浏览图形 mysql监控 zabbix自带mysql模板,所以可以在server1上直接做 创建数据库连接用户 percona数据库模板 清理掉mysql的模块链接 安装并配置好percona的数据库模板 测试脚本 删除tmp下的缓存文…

短链接系统如何设计

shigen坚持日更的博客写手,擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。坚持记录和分享从业两年以来的技术积累和思考,不断沉淀和成长。 今天给大家带来的文章是:《短链接系统如何设计》。在开始之前,先让…

SpringBoot讲义

SpringBoot 文档更新日志 版本更新日期操作描述v1.02021/11/14A基础篇 前言 ​ 很荣幸有机会能以这样的形式和互联网上的各位小伙伴一起学习交流技术课程,这次给大家带来的是Spring家族中比较重要的一门技术课程——SpringBoot。一句话介绍这个技术,…

【基于Kmeans、Kmeans++和二分K均值算法的图像分割】数据挖掘实验三

文章目录 Ⅰ、项目任务要求任务描述:主要任务要求: II、实现过程数据集描述实现描述具体实现过程 III、完整代码代码①代码② Ⅰ、项目任务要求 任务描述: 图像分割是图像处理和计算机视觉中重要的一环,在实际生活中得到了广泛的…

【C++】:关键字+命名空间+输入输出+缺省参数+函数重载+引用

【本节目标】 C关键字命名空间C输入&输出缺省参数函数重载引用 C是在C的基础之上,容纳进去了面向对象编程思想,并增加了许多有用的库,以及编程范式等 熟悉C语言之后,对C学习有一定的帮助,本章节主要目标&#xff…

2023年天猫淘宝双11红包活动入口是什么时候开始至什么时间结束?

​2023年淘宝天猫双11超级红包活动领取时间是从2023年10月24日20:00开始至11月11日23:59结束,淘宝天猫双十一活动时间内每天都可以领取1超级红包最高可得23888元。 2023年天猫淘宝双十一红包使用时间分为2个阶段:第一阶段是从2023年10月31日20:00开始至…

计算机指令、机器码

目录 背景 在软硬件接口中,CPU 帮我们做了什么事? 从编译到汇编,代码怎么变成机器码? 解析指令和机器码 总结延伸 背景 上大学的时候,我们系里教 C 语言程序设计的老师说,他们当年学写程序的时候&…

3.Python-用Python实现MySQL数据库的增删改查

题记 用python实现mysql数据库的增删改查,以下是具体的代码和操作步骤 安装flask模块 pip install flask 安装mysql.connector模块 pip install mysql-connector-python 编写app.py文件 app.py文件如下: 为什么显示不完整??&am…

【Spring】事务传播机制

事务传播机制 一. 事务传播机制是什么二. 为什么需要事务传播机制三. 事务传播机制有哪些四. Spring 事务传播机制演示1. ⽀持当前事务(REQUIRED)2. 不支持当前事务(REQUIRES_NEW)3. 不⽀持当前事务,NEVER 抛异常4. NE…

订单型企业经营分析指标大全(ODOO15/16)

ODOO-ERP搭建完成之后,我们重点是帮客户建立经营分析能力,以下是针对订单型企业的经营分析指标,涵盖业务运营的监控、资产构成、利润、盈亏点计算、资产运营效率等各方面,并且持续完善。 有些企业不重视,觉得自己企业小…

WebAPI+EF连接SQL Server数据库

右击解决方案-添加-新建项目-选择“类库(.NET Framework)”,新建的项目取名叫WebApi1.EF 添加EF: 新建一个ADO实体数据模型 选择DBFirst 数据源选择MySql 填写数据库地址及账号密码 选择实体框架版本 选择在数据库中的表User 到此配置完成&am…