Spring IOC容器的创建过程

2023-10-26

在测试时,经常使用这种方式来创建spring容器

//创建基于注解的springIOC容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopBeanConfig.class);
//创建基于配置文件的springIOC容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-beans.xml");

  无论哪种方式,最终都会调用AbstractApplicationContext的一个重要方法——refresh()。

refresh()方法的spring源码

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 1. Prepare this context for refreshing.为刷新准备上下文
            prepareRefresh();

            // 2. Tell the subclass to refresh the internal bean factory. 告诉子类刷新内部bean工厂
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 3. Prepare the bean factory for use in this context. 准备bean工厂以供在此上下文中使用
            prepareBeanFactory(beanFactory);

            try {
                // 4. Allows post-processing of the bean factory in context subclasses.允许在上下文子类中对bean工厂进行后处理。
                postProcessBeanFactory(beanFactory);

                // 5. Invoke factory processors registered as beans in the context.调用上下文中注册为bean的工厂处理器。
                invokeBeanFactoryPostProcessors(beanFactory);

                // 6. Register bean processors that intercept bean creation.注册拦截bean创建的bean处理器
                registerBeanPostProcessors(beanFactory);

                // 7. Initialize message source for this context. 为此上下文初始化消息源
                initMessageSource();

                // 8. Initialize event multicaster for this context. 为此上下文初始化事件多播程序
                initApplicationEventMulticaster();

                // 9. Initialize other special beans in specific context subclasses. 初始化特定上下文子类中的其他特殊bean
                onRefresh();

                // 10. Check for listener beans and register them. 检查侦听器bean并注册它们
                registerListeners();

                // 11. Instantiate all remaining (non-lazy-init) singletons. 实例化所有剩余的(非惰性初始化)单例
                finishBeanFactoryInitialization(beanFactory);

                // 12. Last step: publish corresponding event. 最后一步:发布相应的事件
                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... 重置Spring核心的普通内省缓存
                resetCommonCaches();
            }
        }
    }

重点步骤简析 :

1. prepareRefresh 准备刷新容器

  (1) initPropertySources() 自定义属性设置,空方法,留给子类继承
 
  (2) getEnvironment.validateRequiredProperties 首先获取环境配置,然后校验必需属性

  (3) this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); 初始化事件监听器

  (4) this.earlyApplicationEvents = new LinkedHashSet<>(); 初始化早期事件

2. obtainFreshBeanFactory 获取组件工厂

  (1) refreshBeanFactory 新建一个组件工厂,类型为DefaultListableBeanFactory, 然后对这个组件工厂设置了一个序列化ID
  (2) getBeanFactory 返回刚刚创建的组件工厂

3. prepareBeanFactory 对组件工厂做各种预处理设置

  (1) 在组件工厂中设置类加载器、属性解析器等
  
  (2) 在组件工厂中添加部分组件后置处理器,例如ApplicationContextAwareProcessor、ApplicationListenerDetector

  (3) 在组件工厂中设置忽略自动注入的接口

  (4) 设置自动装配规则

  (5) 在组件工厂中注册一些组件,例如环境配置ConfigurableEnvironment

4. postProcessBeanFactory 组件工厂的后置处理工作
5. invokeBeanFactoryPostProcessors 执行组件工厂后置处理器

这一步是在组件工厂的标准初始化(1-4)之后进行的,主要是执行BeanFactoryPostProcessor及其子接口的。

BeanFactoryPostProcessor的子接口主要是指BeanDefinitionRegistryPostProcessor,可以向容器中注册新的组件,这个接口的特点是有两个方法,一个是自身的postProcessBeanDefinitionRegistry,另一个继承自BeanFactoryPostProcessor的postProcessBeanFactory,从源码可以看出,spring会先执行BeanDefinitionRegistryPostProcessor类型的组件的自身方法,然后执行其继承方法,最后才调用非BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor的后置处理方法

  (1) 从容器器中获取BeanDefinitionRegistryPostProcessor类型的组件。
  
  (2) 将BeanDefinitionRegistryPostProcessor类型的组件按照顺序分类并排序,即是否实现了PriorityOrdered、Ordered接口。

  (3) 依次执行实现了PriorityOrdered接口的、实现了Ordered接口的、没有实现任何顺序接口的组件的postProcessBeanDefinitionRegistry方法。

  (4) 执行所有BeanDefinitionRegistryPostProcessor组件的postProcessBeanFactory方法。

  (5) 从容器中获取其他的BeanFactoryPostProcessor类型的组件,即不是BeanDefinitionRegistryPostProcessor类型的。

  (6) 剩下的步骤跟上面类似,就是先按照实现的顺序接口分类,在每个类别下排序,然后依次执行它们的postProcessBeanFactory方法。

6. registerBeanPostProcessors 注册组件后置处理器,这种处理器用于拦截bean的创建过程

  beanPostProcessor有很多子接口,每种子接口的执行时机各有不同

  |-DestructionAwareBeanPostProcessor

  |-InstantiationAwareBeanPostProcessor

  |-MergedBeanDefinitionPostProcessor

  |-SmartInstantiationAwareBeanPostProcessor

  (1) 获取所有的beanPostProcessor的组件名
 
   (2) 将所有的组件按优先顺序分为三类:

      |-实现了PriorityOrdered接口的列表priorityOrderedPostProcessors

     |-实现了Ordered接口的列表orderedPostProcessors

     |-没有实现任何顺序接口的列表nonOrderedPostProcessors

  还有一种特殊情况,凡是MergedBeanDefinitionPostProcessor类型的,都放在internalPostProcessors中

  (3) 注册priorityOrderedPostProcessors

  (4) 注册orderedPostProcessors

  (5) 注册nonOrderedPostProcessors

  (6) 注册internalPostProcessors

  (7) 注册ApplicationListenerDetector,它的作用是在组件初始化之后判断其是否为ApplicationListner类型,如果是,则将其添加进容器的监听器集合。

7. initMessageSource 初始化消息源组件,用于消息绑定、消息解析等功能,并且提供国际化解决方案

  (1) 获取beanFactory。
  
  (2) 判断beanFactory中是否包含id为messageSource的组件。

  (3) 如果已存在,则赋值给容器的messageSource属性,这种情况是我们自己在容器中注册了这个组件。

  (4) 如果不存在,则新建一个DelegatingMessageSource,并赋值给容器的messageSource属性, 然后在beanFactory中注册这个新组件,并设置其id为messageSource。

8. initApplicationEventMulticaster 初始化事件广播器

  (1) 获取beanFactory
  
  (2) 判断beanFactory中是否存在id为applicationEventMulticaster的组件。

  (3) 如果已存在,则赋值给容器的applicationEventMulticaster属性,这种情况是我们自己在容器中注册了这个组件。

  (4) 如果不存在,则新建一个SimpleApplicationEventMulticaster,并赋值给容器的applicationEventMulticaster属性,然后在beanFactory中注册这个新组件,并设置其id为applicationEventMulticaster。

9. onRefresh 没有任何操作,留给子类继承的,我们可以自定义子容器,在重写方法中做一些我们想要的操作

10. registerListeners 注册事件监听器

  (1) 获取容器的属性applicationListeners,这是一个事件监听器的集合,将集合中的每个元素都添加进事件广播器
  (2) 从容器中获取所有ApplicationListener类型的组件,将这些组件添加进事件广播器
  (3) 发布早期事件,即容器的earlyApplicationEvents属性(参考第1(4)步),然后清空早期事件

11. finishBeanFactoryInitialization 完成剩下的单实例bean的初始化

  (1) 进入DefaultListableBeanFactory.preInstantiateSingletons方法,获取容器中所有的组件id列表。
  
  (2) 遍历组件id列表,对每个组件,获取其组件定义信息,即RootBeanDefinition。

  (3) 从组件定义信息中筛选掉抽象类、非单实例、懒加载的,这些bean在创建容器时并不初始化,另外还有工厂组件,即实现了FactoryBean接口的,需要另外一套逻辑进行初始化。

  (4) 从缓存中获取单实例bean,即DefaultSingletonBeanRegistry类的singletonObjects属性,所有被创建过的单实例bean都会被缓存在这个映射中;如果缓存中存在,说明这个组件之前被创建过,直接返回。
  (5) 如果缓存中不存在,则开始新建

  ① 将组件标记为已创建,即将其id存入AbstractBeanFactoryalreadyCreated属性中。

   ② 获取组件的定义信息,即RootBeanDefinition。

  ③ 从定义信息中获取该组件依赖的组件,如果存在,则重新从第11(4)步开始执行,创建这些依赖的组件。

  ④ 创建完依赖组件(如果存在)之后,以下开始正式新建目标组件。

  ⑤ 给组件后置处理器一个机会用代理对象代替目标对象,即执行InstantiationAwareBeanPostProcessor类型的组件后置处理器的postProcessBeforeInstantiation、postProcessAfterInitialization方法。

  ⑥ Allow post-processors to modify the merged bean definition,即执行MergedBeanDefinitionPostProcessor类型组件后置处理器的postProcessMergedBeanDefinition方法。

  ⑦ 执行AbstractAutowireCapableBeanFactory.populateBean方法,即属性赋值。在属性赋值之前,首先拿到InstantiationAwareBeanPostProcessor类型的组件后置处理器,并执行postProcessAfterInstantiation、postProcessProperties、postProcessPropertyValues方法;然后才执行该类的applyPropertyValues方法,利用反射调用组件的setter方法进行属性赋值。

  ⑧ 执行以下三种aware接口的方法:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware

  ⑨ 执行组件后置处理器的初始化前方法,即BeanPostProcessor.postProcessBeforeInitialization

  ⑩ 执行组件的初始化方法,即InitializingBean.afterPropertiesSet,以及在容器中自定义的initMethod。

  ⑪ 执行组件后置处理器的初始化后方法,即BeanPostProcessor.postProcessAfterInitialization

  ⑫ 如果需要,注册组件的销毁方法,例如DisposableBean.destroy,以及在容器中自定义的destroyMethod 这里只是注册,并不调用。

  (6) 通过第11(5)步,单实例bean已经创建并初始化完成,接着,会调用AbstractBeanFactory的父类方法——DefaultSingletonBeanRegistry.getSingleton方法,将新建的bean存入singletonObjects属性中,即缓存

  (7) 回到DefaultListableBeanFactory.preInstantiateSingletons方法(见第11(1)步)

  如果新建的bean实现了SmartInitializingSingleton接口,则执行afterSingletonsInstantiated回调方法。

12. finishRefresh 完成容器刷新

  (1) 初始化生命周期处理器(LifecycleProcessor),先从BeanFactory中按类型获取,如果没有就新建一个DefaultLifecycleProcessor,并注册进BeanFactory

  (2) 获取上一步注册的生命周期处理器,回调其onRefresh方法

  (3) 发布容器刷新事件,即ContextRefreshedEvent。

转载自:https://www.cnblogs.com/dubhlinn/p/10764845.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring IOC容器的创建过程 的相关文章

  • 网络编程3——TCP Socket实现的客户端服务器通信完整代码(详细注释帮你快速理解)

    文章目录 前言 一 理论准备 Socket套接字是什么 TCP协议的特点 二 TCP 流套接字提供的API ServerSocket API Socket API 三 代码实现请求响应式 客户端服务器 服务器 客户端 疑惑解答 为什么服务器
  • 零基础自学计算机方法大全

    欢迎入读 尚学堂给同学们带来全新的Java300集课程啦 java零基础小白自学Java必备优质教程 学习从来没有捷径 只有学成之后才会一切是那么简单 想要学会编程 一定要有坚定的信念 1 选方向 定目标 首先你需要做好功课 了解计算机的分
  • javaee之黑马乐优商城4

    商品规格与数据结构 下面来说一下数据库的设计与分析 其实对于spu这张表来说 大体设计还是比较好设计的 看一下下面这张图是一个产品的规格参数 上面主体就是一个规格参数 基本信息又是一个规格参数 这里就是涉及到了一个商品的具体信息 sku就是
  • 利用Java EE相关技术实现一个简单的购物车系统

    利用JSP编程技术实现一个简单的购物车程序 具体要求如下 1 用JSP编程实现一个登录页面 登录信息中有用户名和密码 分别用两个按钮来提交和重置登录信息 另外 登录页面请实现记住密码功能 2 编写一个JSP程序来获取用户提交的登录信息并查询
  • File类的知识

    File 文章目录 File 概述 构造方法 抽象路径 成员方法 创建 删除 判断和获取和遍历 判断 获取 遍历 概述 java编写的一个专门用于描述计算机中的文件和文件夹的类 1 是文件和目录路径名的抽象表示 2 文件和目录是可以通过Fi
  • IntelliJ Idea 常用快捷键 列表(实战终极总结!!!!)

    自动代码 常用的有fori sout psvm Tab即可生成循环 System out main方法等boilerplate样板代码 例如要输入for User user users 只需输入user for Tab 再比如 要输入Dat
  • java基础语法

    java基础语法 1 Java概述 1 1 Java语言发展史 了解 1 2 Java语言跨平台原理 理解 1 3 JRE和JDK 记忆 1 4 JDK的下载和安装 应用 1 4 1 下载 1 4 2 安装 1 4 3 JDK的安装目录介绍
  • 在centos7中安装docker

    一 前置条件 64 bit 系统 kernel 3 10 CentOS 7 1 检查 使用 uname r 检查 kernel 版本 uname r 3 10 0 327 el7 x86 64 二 安装 yum安装方式 1 使用 sudo
  • 多线程(六):多线程案例

    多线程最最经典案例就是上一章的单例设计模式 当然除了单例设计模式 还有其他的案例 本章就 一一 来介绍 阻塞队列 这里是第一次提到阻塞队列这个东西 简单介绍一下 什么是阻塞队列 阻塞队列 BlockingQueue 是一个支持两个附加操作的
  • 2.HTTP协议(Requset、Response)

    目录 http协议 http报文解析 Http请求报文 浏览器 gt 服务器 1 请求行 2 请求头 3 空行 java处理http请求的常用方法 Http响应报文 服务器 gt 浏览器 1 响应行 2 响应头 3 响应正文 实体内容 ja
  • TCP协议,TCP报头及特点基础介绍

    目录 TCP协议 TCP协议特点 TCP协议适用场景 TCP包首部 什么是TCP连接 如何唯一确定一个TCP连接 有一个 IP 的服务器监听了一个端口 它的 TCP 的最大连接数是多少 TCP与UDP的区别 TCP协议 TCP是一种面向字节
  • EL表达式向select中赋值

    在使用el表达式的时候 有时需要向select下拉菜单中赋值 可以使用三目运算法进行赋值
  • 多线程(九):JUC组件

    在来时juc组件前 我们先把上一章遗漏的部分给补上 synchronized 实现策略 锁升级 无锁 gt 偏向锁 gt 轻量级锁 gt 重量级锁 还有一个 锁消除 锁消除即删除不必要的加锁操作 JVM在运行时 对一些 在代码上要求同步 但
  • Spring学习笔记总结

    第一章 引言 1 EJB存在的问题 2 什么是Spring Spring是一个轻量级的JavaEE解决方案 整合众多优秀的设计模式 轻量级 1 对于运行环境是没有额外要求的 开源 tomcat resion jetty 收费 weblogi
  • MyBatis中Mapper接口和dao区别是什么?

    MyBatis中的mapper接口相当于以前的dao 但是区别在于 mapper仅仅是接口 我们不需要 提供实现类 public interface UserMapper 添加用户信息 int insertUser
  • @Resource注解是什么作用,和@bean区别是什么?

    Resource 注解就像是 Java 开发的快递小哥 专门用来送依赖关系到你的代码门口 它的主要工作就是帮你实现依赖注入 把其他组件 比如类 对象 bean 啥的 送到你需要的地方 具体来说 依赖注入 Resource 负责把其他组件注入
  • 【计算机毕业设计】精品课程在线学习系统

    如今社会上各行各业 都喜欢用自己行业的专属软件工作 互联网发展到这个时候 人们已经发现离不开了互联网 新技术的产生 往往能解决一些老技术的弊端问题 因为传统精品课程学习信息管理难度大 容错率低 管理人员处理数据费工费时 所以专门为解决这个难
  • J2EE常见面试题(一)

    StringBuilder和StringBuffer的区别 String 字符串常量 不可变 使用字符串拼接时是不同的2个空间 StringBuffer 字符串变量 可变 线程安全 字符串拼接直接在字符串后追加 StringBuilder
  • 【计算机毕业设计】二手家电管理平台

    时代在飞速进步 每个行业都在努力发展现在先进技术 通过这些先进的技术来提高自己的水平和优势 二手家电管理平台当然不能排除在外 二手家电管理平台是在实际应用和软件工程的开发原理之上 运用java语言以及前台VUE框架 后台SpringBoot
  • 【计算机毕业设计】宝鸡文理学院学生成绩动态追踪系统

    研究开发宝鸡文理学院学生成绩动态追踪系统的目的是让使用者可以更方便的将人 设备和场景更立体的连接在一起 能让用户以更科幻的方式使用产品 体验高科技时代带给人们的方便 同时也能让用户体会到与以往常规产品不同的体验风格 与安卓 iOS相比较起来

随机推荐

  • 你的个人隐私信息泄露了吗?大数据时代如何保护好个人隐私?

    很多人在上网或者日常生活中 都需要填写各种个人信息 身份证号码 银行卡号 联系电话 家庭住址等等 这些信息虽然经过加密处理 但是对于拥有专业网络知识的黑客来说 这些所谓的加密方式都只不过是一层薄纸 一捅就破 比如说 2018年8月底 在美上
  • qt添加资源文件后编译失败,提示Qt:Error:No rule to make target ’ … /…/??.png’,needed by ‘debug/qrc_qrc.cpp’ stop

    提要 项目本来编译没有问题 资源文件忘记添加了 于是添加资源文件后 编译没有通过 提示错误 Qt Error No rule to make target png needed by debug qrc qrc cpp stop 解决方法
  • 基于AntDesignVue的自定义Dropdown下拉选择组件

    组件效果 组件代码
  • Kettle8.2转换组件之排序与去除重复记录

    Kettle8 2转换组件之排序与去除重复记录 一 相关说明 二 设计转换 三 转换配置 四 运行转换 五 查看结果 一 相关说明 需求说明 从Excel读取数据 去除其中重复的字段 并把结果数据保存在数据库表中 排序记录组件说明 排序记录
  • 圆的碰撞检测

    bool CollisionBetweenCircles circle c1 circle c2 bool hit float distanceOfCenter sqrt pow c1 center x c2 center x 2 pow
  • Python基础入门笔记(一)

    前言 认识Python 既然学习 Python 那么至少得了解下这门语言 知道 Python 代码执行过程吧 Python 的历史有兴趣的百度百科下就有 这个不多说了 1 我们先来了解下什么是解释型语言和编译型语言 计算机是不能够识别高级语
  • 【毕业设计】 基于Stm32的家庭智能监控系统 - 单片机 图像识别 人体检测 AI

    0 前言 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的毕设题目缺少创新和亮点 往往达不到毕业答辩的要求 这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求 为了大家能够顺利以及最少的精力通过毕设 学长分享优质毕业设计项
  • 【NSGA2三维路径规划】非主导排序遗传算法2求解无人机三维路径规划【含Matlab源码 1455期】

    一 无人机简介 0 引言 随着现代技术的发展 飞行器种类不断变多 应用也日趋专一化 完善化 如专门用作植保的大疆PS X625无人机 用作街景拍摄与监控巡察的宝鸡行翼航空科技的X8无人机 以及用作水下救援的白鲨MIX水下无人机等 决定飞行器
  • 获取当前时间点的毫秒值,对std::chrono类的简单小结

    C 11 std chrono主要类与函数总结 duration time point system clock duration cast f 先来看一段获取当前毫秒值的代码 我们根据这个代码进行拆分学习 include
  • windows 执行bat脚本

    bat脚本中运行另外一个bat脚本 call 命令 call1 bat内容如下 echo running call1 call2 bat内容如下 echo off echo start call call1 bat echo running
  • Ogre 界面(Overlay)

    Ogre 界面 Overlay 标签 border脚本buttontemplatesplugins引擎 2011 10 16 23 12 4725人阅读 评论 2 收藏 举报 分类 引擎技术 9 这里的界面是指菜单 HUD及提示信息框在内的
  • 各个join区别

    在数学中 笛卡尔乘积是指两个集合X和Y的笛卡尓积 Cartesian product 又称直积 表示为X Y 第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员 假设集合A a b 集合B 0 1 2 则两个集合的笛卡尔积为
  • 基于MATLAB的几种图像分割算法

    最大类间方差法 基本思路是根据直方图以某一会灰度为阈值将图像分割成两部分 计算两组的方差 当被分成的两组之间的方差最大时 这个灰度为阈值灰度值 img imread C Users dell Desktop 前单图 3 3 JPG 原图 I
  • 最新版本Android-Studio2.1.2 Windows7 64bit系统下搭建Android开发环境

    windows7 64bit系统下搭建Android开发环境 最新版本Android Studio2 1 2 注 现在在使用i MX6Q开发板做嵌入式系统开发 跑的是Android系统 想在开发板写一些测试程序 因此搭建了Android开发
  • FreeRTOS 事件组

    实现功能 当任务A B完成后执行串口任务 不同任务用不同的位表示 configUSE 16 BIT TICKS 1 bitx 0 7 configUSE 16 BIT TICKS设置为0 bitx 0 23 串口任务的头文件 ifndef
  • QNX操作系统简介

    QNX是商业类Unix实时操作系统 主要针对嵌入式系统市场 该产品开发于20世纪80年代初 后来改名为QNX软件系统公司 QNX软件系统公司 黑莓公司旗下子公司 是全球领先的创新嵌入式技术供应商 包括中间件 开发工具和操作系统 QNX Ne
  • Django配置mysql数据库

    默认使用SQLite3数据库 1 本地已安装mysql数据库 或者使用已存在的数据库 创建表空间 存放项目中的表 create database bobmydata show databases 2 安装数据连接工具PyMySQL pip
  • eclipse中jsp自动提示慢的问题

    这几天用eclipse编写jsp代码 发现点了 引导符后 系统提供的自动提示出奇的慢 于是开始网络求助 搞清了原因 eclipse在编写jsp时 当点下引导符后 要去相应的javadoc 中寻找相应的解释 而他默认的寻找路径是 sun的网站
  • Kernel panic - not syncing: Requested init /linuxrc failed (error -13).

    开发板平台exynos 4413 使用busybox 1 31 1制作ext4根文件系统 Kernel panic not syncing Requested init linuxrc failed error 13 这是一个巨坑无比的错误
  • Spring IOC容器的创建过程

    在测试时 经常使用这种方式来创建spring容器 创建基于注解的springIOC容器 ApplicationContext applicationContext new AnnotationConfigApplicationContext