Spring IOC容器初始化主流程

2023-11-07

1. Spring IOC容器体系

IoC容器是Spring的核⼼模块,是抽象了对象管理、依赖关系管理的框架解决⽅案。 Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器 必须遵从的⼀套原则,具体的容器实现可以增加额外的功能,⽐如我们常⽤到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容,AnnotationConfigApplicationContext 则是包含了注解解析等⼀系列的内容。 Spring IoC 容器继承体系⾮常聪明,需要使⽤哪个层次⽤哪个层次即可,不必使⽤功能⼤⽽全的。
BeanFactory顶级接口的方法栈如下:
在这里插入图片描述
BeanFactory的继承和实现体系:
在这里插入图片描述

2. Bean生命周期关键时机点

  1. Bean对象初始化:非延迟加载的Bean对象,在容器初始化过程中就创建完成了。
  2. 分析构造函数调⽤情况:构造函数的调⽤时机在AbstractApplicationContext类refresh⽅法的finishBeanFactoryInitialization(beanFactory)处;
  3. 分析 InitializingBean 之 afterPropertiesSet 初始化⽅法调⽤情况: InitializingBean中afterPropertiesSet ⽅法的调⽤时机也是在AbstractApplicationContext类refresh⽅法的finishBeanFactoryInitialization(beanFactory);
  4. 分析BeanFactoryPostProcessor 初始化和调⽤情况:
    BeanFactoryPostProcessor 初始化在AbstractApplicationContext类refresh⽅法的invokeBeanFactoryPostProcessors(beanFactory);
    postProcessBeanFactory 调⽤在AbstractApplicationContext类refresh⽅法的invokeBeanFactoryPostProcessors(beanFactory);
  5. 分析 BeanPostProcessor 初始化和调⽤情况:
    BeanPostProcessor 初始化在AbstractApplicationContext类refresh⽅法的 registerBeanPostProcessors(beanFactory);
    postProcessBeforeInitialization 调⽤在AbstractApplicationContext类refresh⽅法的 finishBeanFactoryInitialization(beanFactory);
    postProcessAfterInitialization 调⽤在AbstractApplicationContext类refresh⽅法的 finishBeanFactoryInitialization(beanFactory);
  6. 总结:通过上述内容可以得出,Bean对象创建的⼏个关键时机点代码层级的调⽤都在AbstractApplicationContext 类 的 refresh ⽅法中,可⻅这个⽅法对于Spring IoC 容器初始化来说相当关键。

3. IOC容器初始主流程

由上面分析的内容,可以看出IOC容器的初始化主要是在AbstractApplicationContext类refresh⽅法中,下面分析一下refresh方法的流程内容:
第一步:刷新预处理

prepareRefresh();

第二步:创建BeanFactory: 默认实现的是ConfigurableListableBeanFactory

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

第三步:BeanFactory预备工作,比如Context的类加载

prepareBeanFactory(beanFactory);

第四步:BeanFactory准备⼯作完成后进⾏的后置处理⼯作

postProcessBeanFactory(beanFactory);

第五步:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean

invokeBeanFactoryPostProcessors(beanFactory);

第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执行

registerBeanPostProcessors(beanFactory);

第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);

initMessageSource();

第八步:初始化事件派发器

initApplicationEventMulticaster();

第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑

onRefresh();

第十步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器Bean

registerListeners();

第十一步:初始化所有剩下的⾮懒加载的单例bean;初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性);填充属性;初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、 init-method⽅法);调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处理

finishBeanFactoryInitialization(beanFactory);

第十二步:完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事件(ContextRefreshedEvent)

finishRefresh();

整体流程如下所示:

@Override
public void refresh() throws BeansException, IllegalStateException {
   //对象加锁
   synchronized (this.startupShutdownMonitor) {
      // 第一步:刷新前的预处理
      prepareRefresh();

      /**
       * 第二步:
       * 获取BeanFactory;默认实现是ConfigurableListableBeanFactory,
       * 加载BeanDefinition并注册到BeanDefinitionRegistry
          */
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      /**
       * 第三步:(BeanFactory进⾏⼀些设置,⽐如context的类加
       * 载器等)
       */
      prepareBeanFactory(beanFactory);

      try {
         /**
          * 第四步: BeanFactory准备⼯作完成后进⾏的后置处理⼯作
          */
         postProcessBeanFactory(beanFactory);

         /**
          * 第五步:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
          */
         invokeBeanFactoryPostProcessors(beanFactory);

         /**
          * 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执
          */
         registerBeanPostProcessors(beanFactory);

         /**
          * 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
          */
         initMessageSource();

         /**
          * 第⼋步:初始化事件派发器
          */
         initApplicationEventMulticaster();

         /**
          * 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
          */
         onRefresh();

         /**
          * 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器
          * bean
          */
         registerListeners();

         /**
          * 第⼗⼀步:
          * 初始化所有剩下的⾮懒加载的单例bean
          * 初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
          * 填充属性
          * 初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、 init-method⽅法)
          * 调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处
          */
         finishBeanFactoryInitialization(beanFactory);

         /**
          * 第⼗⼆步:
          * 完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事
          * 件(ContextRefreshedEvent)
          */
         finishRefresh();
      }

      catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }

         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();

         // Reset 'active' flag.
         cancelRefresh(ex);

         // Propagate exception to caller.
         throw ex;
      }

      finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
      }
   }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring IOC容器初始化主流程 的相关文章

  • 无论线程如何,对象是否总是能看到其最新的内部状态?

    假设我有一个带有简单整数计数变量的可运行对象 每次可运行对象运行时该变量都会递增 该对象的一个 实例被提交以在计划的执行程序服务中定期运行 class Counter implements Runnable private int coun
  • 如何在ArrayList中的特定位置插入对象

    假设我有一个大小为 n 的对象的 ArrayList 现在我想在特定位置插入另一个对象 假设在索引位置 k 大于 0 且小于 n 并且我希望索引位置 k 处及其之后的其他对象向前移动一个索引位置 那么有没有什么方法可以直接在Java中做到这
  • 类型已知,但方法指的是缺失类型

    我对 java 和 Eclipse 不太有经验 但遇到以下问题 我正在写类似的东西 Point3D myPoint myClass myMethod arg 我收到错误 方法 myMethod myType arg 引用缺失的类型 Poin
  • java 中的梵文 i18n

    我正在尝试使用来自互联网的示例 ttf 文件在 java 中使用 i18n 进行梵文 印地文 我可以加载资源包条目 还可以加载 ttf 并设置字体 但它不会根据需要呈现 jlabel 它显示块代替字符 如果我在 Eclipse 中调试 我可
  • Selenium 和 TestNG 同时使用“dependsOn”和“priority =”问题

    我正在努力在 GUI 自动化测试中实现更好的工作流程控制 我首先从dependsOn开始 但很快发现缺点是如果一个测试失败 则套件的整个其余部分都不会运行 所以我改用 priority 但看到了意外的行为 一个例子 Test priorit
  • 未注入带有 JPA2 的 Apache Ignite 2.7 IgniteRepository

    使用在 Web 上建立的 guildes 我使用 Spring Data JPA 2 应用程序制作了简单的 Spring Boot 2 仅在 2 7 版本中才向 Apache Ignite 添加了 Spring Boot JPA 2 支持
  • 如何避免Eclipse在将类名放在注释中时导入类,以便checkstyle稍后不会抱怨?

    有时我将类名放在方法或类的注释中只是为了引用 但是 Eclipse 会自动执行导入并在文件中留下导入语句 这会导致稍后出现 未使用的导入 检查样式错误 当我在注释中输入类名时 是否可以更改一些配置以避免 Eclipse 自动导入 人们不同意
  • Spring HATEOAS 和 HAL:更改 _embedded 中的数组名称

    我正在尝试使用 Spring HATEOAS 构建符合 HAL 的 REST API 经过一番摆弄后我终于开始工作了mostly正如预期的那样 示例 输出现在看起来像这样 links self href http localhost 808
  • 对对象集合进行排序[重复]

    这个问题在这里已经有答案了 如果我有一个简单的字符串列表 List
  • ActiveMQ JNDI 查找问题

    尝试使用 JNDI 运行以下 ActiveMQ http activemq apache org jndi support html http ActiveMQ 20JNDI 并且我的 jboss server node lib 文件夹中有
  • 错误膨胀类 android.support.design.widget.NavigationView [启动时崩溃]

    该应用程序应该有一个导航抽屉 可以从左侧拉出并显示各种活动 但是一旦将导航栏添加到 XML Activity homescreen 文档中 应用程序一启动就会崩溃 主屏幕 java package com t99sdevelopment c
  • 接口是否像对象一样对待?

    为什么下面的代码可以工作 interface I class A implements I public String toString return in a class B extends A public String toStrin
  • JPA Web 应用程序管理策略

    我们目前正在开发一个 J2EE Web 应用程序 使用 JPA 作为我们的数据访问层 我们目前正在研究几种不同的策略来在我们的应用程序中利用缓存 Create an EntityManager per request 在请求范围内获取缓存
  • 获取 Future 对象的进度的能力

    参考 java util concurrent 包和 Future 接口 我注意到 除非我弄错了 只有 SwingWorker 实现类才能启动冗长的任务并能够查询进度 这就引出了以下问题 有没有办法在非 GUI 非 Swing 应用程序 映
  • 无法连接到docker中的elasticsearch容器

    我正在尝试使用 docker 的官方 elasticsearch 镜像 我遵循了本指南 https www elastic co guide en elasticsearch reference current docker html但是当
  • Proguard 正在破坏我的清洁度。 Gson 和泛型

    我有一个从持久性加载信息的函数 我只是以一种非常简单的方式告诉它的类型 该类称为SharedPreferencesHelper kt所以它是一个真正的生活问题解决者 fun
  • 为什么不能在 if 语句中声明变量?

    以下 Java 代码无法编译 int a 0 if a 1 int b 0 if a 1 b 1 为什么 不能有任何代码路径导致程序将 1 分配给b无需先声明 我突然想到b的变量范围可能仅限于第一个if声明 但后来我不明白为什么 如果我实在
  • 在java中执行匿名pl/sql块并获取结果集

    我想执行匿名 PL SQL 并需要获取结果集对象 我得到了可以通过在 PL SQL 块内使用游标来完成的代码 但 PL SQL 块本身将以文本形式来自数据库 所以我无法编辑该 PL SQL 块 并且它只会返回两个值 其列名始终相同 它将返回
  • Firebase:用户注册后如何进行电话号码验证?

    所以我知道我可以使用电子邮件验证或电话号码验证 但我想做的是在用户注册或登录后进行电话号码验证 如何连接这两种身份验证方法 最后 Firebase中是否有一个函数可以检查用户是否通过电话号码验证 谢谢 即使用户已通过身份验证 您仍然可以使用
  • Java时区混乱

    我正在运行 Tomcat 应用程序 并且需要显示一些时间值 不幸的是 时间快到了 还有一个小时的休息时间 我调查了一下 发现我的默认时区被设置为 sun util calendar ZoneInfo id GMT 08 00 offset

随机推荐

  • (三-一)IPC-邮箱通信

    一个线程想发送信息到另一个线程 最直接的方式是用全局变量 但是全局变量难以管理 而且一个线程希望等待信息的时候把自己挂起 需要有一个方便的方案 邮箱通信是操作系统中常用的一种通信机制 如图所示 很多操作系统 如RT THREAD 邮箱其实也
  • springboot+spring-security+ajax+前后端分离解决Authorization请求头跨域问题

    security ajax 前后端分离解决Authorization请求头跨域问题 背景 后端采用 springboot spring security oauth2开发 前台采用纯静态页面的形式开发 以此做到前后端分离 采用token的形
  • Python实现线性回归

    文章目录 一 线性回归原理 1 构造模型 2 构建损失函数 3 优化损失 二 设计方案 1 准备数据 2 构造损失函数 3 优化损失 三 代码实现 四 总结 一 线性回归原理 1 构造模型 y w1x1 w2x2 b 2 构建损失函数 均方
  • kolla-ansible部署openstack+opendaylight

    1 环境准备 准备三台机器 分别作为OpenStack的controller和compute节点 OpenDayLight节点 另外把controller作为本次的部署节点 其中controller和compute节点各两张网卡 odl节点
  • 网站部署到服务器后乱版,nginx配置双网站后,域名乱跳转的解决方法

    前言 今天 小焦给大家要讨论的问题就是一台服务器配置两个网站后 域名错误的问题 因为个人需求 我在一台nginx配置的服务器上部署了两个网站 一个是纯html和css写的静态网站 一个就是我用wordpress做的这个现在的这个个人博客网站
  • 【数字信号处理2】IIR 滤波器设计

    一 实验目的 1 掌握冲激响应法和双线性变换法设计IIR滤波器的原理及具体设计方法 熟悉用双线性设计法设计低通 带通和高通IIR数字滤波器的计算机程序 2 熟悉模拟Butterworth滤波器的设计 掌握冲激响应法和双线性变换法设计数字II
  • C++——命名空间(namespace)

    目录 1 C语言命名冲突 2 命名空间定义 3 命名空间使用 可能大家在看别人写的C 代码中 在一开始会包这个头文件 include
  • Mac下抓包工具Charles的使用

    一 简介 Charles是目前最强大的http调试工具 在界面和功能上远强于Fiddler 1 1 界面功能 工具条包含了Charles的大部分功能 右键请求出现菜单 Charles的右键菜单功能比fiddler强大太多了 双击请求进入列表
  • Python+Selenium框架设计篇1- 价值好几K的框架,不看别后悔,过时不候

    1 什么是自动化测试框架 在了解什么是自动化测试框架之前 先了解一下什么叫框架 框架是整个或部分系统的可重用设计 表现为一组抽象构件及构件实例间交互的方法 另一种定义认为 框架是可被应用开发者定制的应用骨架 前者是从应用方面 而后者是从目的
  • 8579 链式线性表的基本操作

    8579 链式线性表的基本操作 题干 8579 链式线性表的基本操作 时间限制 1000MS 代码长度限制 10KB 提交次数 5567 通过次数 2176 题型 编程题 语言 G GCC Description 编写算法 创建一个含有n个
  • 初步认识Thread网络

    Thread网络 说明 本文档内容参考自 https openthread google cn guides 是基于这个官方文档内容进行的添加一些个人理解的介绍文档 文档内容仅能作为对thread 网络的一个概念学习和参考 基本概念 Thr
  • 前端页面如何适应不同屏幕分辨率常用做法

    为什么80 的码农都做不了架构师 gt gt gt 1 根据几个浏览器分辨率统计平台得到数据现在使用1200分辨率以下用户极少 但我们CSS布局时仍然需要至少考虑1024px分辨率用户 2 使用css media 属性针对不同的屏幕加载不同
  • MarkDown软件Typora图片上传解决方案:Typora+PicGo图床

    MarkDown软件Typora图片上传解决方案 Typora PicGo图床 一 问题描述 今天在网上学习Java开发环境配置 想在CSDN上写篇博客记录安装及环境配置过程 经过在网上的调研 相当一部分的程序员都喜欢用一款名为 Typor
  • unity 射线检测真机失效_用Unity的RaycastCommand实现子弹的碰撞检测碰到的大坑

    首先放个视频来展示一下 星之海的阿斯特莉娅 最新的开发进度吧 加入了防空系统 可以拦截敌人的导弹 https www bilibili com video BV1i541167BY 假装这里有视频 b站换成bv号了 这里好像还不支持 然后来
  • 计算机毕业设计-基于SSM的音乐推荐管理系统

    项目摘要 中国风音乐推介网站近年来已成为风靡全球的新兴艺术形式 国内涌现出了大批优秀 有才华的爱好者和许多经久不衰的经典作品 中国风音乐推介网站的兴起打破了音乐界格局 也突破了原有分类唱法发展中的瓶颈 为声乐艺术的发展开辟了新篇章 这种新兴
  • 关于mapper在service层注入报错

    关于mapper在service层注入报错 有如下三种解决的方案 1 在主类Application class上添加 MapperScan basePackages 自己的mapper包 2 在mapper接口上添加 Mapper 和第一种
  • MySQL优化五-高性能的8个索引策略

    正确创建和使用索引策略是实现高性能查询的基础 本文总结7个索引策略 一 独立的列 独立的列是指索引不能是表达式的一部分 也不能是函数的参数 mysql gt select id from actor where id 1 5 错误 mysq
  • 用Python快速将ppt制作成配音视频课件的方法

    老猿Python博文目录 一 引言 老猿从来没有录播个视频课件 但最近有要求在一周内必须录制一个视频课件 为此花了3天时间准备ppt 花了一个小时录播了一个20多分钟的课件 由于第一次干这个活 讲课时情绪还是有点紧张 导致录播的语音出现了各
  • ABAP OPEN SQL详解

    本章目录 概要 OPEN SQL 读取数据 1 概要 1 1 R 3体系结构 学习SQL之前先了解一下R 3体系结构 如 图1 所示 SAP R 3一共分为三层结构 其中应用层和数据库层由单独的系统构成 1 表示层 表示层 Presenta
  • Spring IOC容器初始化主流程

    1 Spring IOC容器体系 IoC容器是Spring的核 模块 是抽象了对象管理 依赖关系管理的框架解决 案 Spring 提供了很多的容器 其中 BeanFactory 是顶层容器 根容器 不能被实例化 它定义了所有 IoC 容器