文档章节

Spring 之 IOC 初始化总结

Java搬砖工程师
 Java搬砖工程师
发布于 10/23 17:38
字数 1303
阅读 17
收藏 7

IOC 容器的初始化过程分为三步骤:

  • Resource 定位
  • BeanDefinition 的载入和解析
  • BeanDefinition 注册    

  • Resource 定位。我们一般用外部资源来描述 Bean 对象,所以在初始化 IOC 容器的第一步就是需要定位这个外部资源。
  • BeanDefinition 的载入和解析。装载就是 BeanDefinition 的载入。BeanDefinitionReader 读取、解析 Resource 资源,也就是将用户定义的 Bean 表示成 IOC 容器的内部数据结构:BeanDefinition。在 IOC 容器内部维护着一个 BeanDefinition Map 的数据结构,在配置文件中每一个都对应着一个BeanDefinition对象。
  • BeanDefinition 注册。向IOC容器注册在第二步解析好的 BeanDefinition,这个过程是通过 BeanDefinitionRegistery 接口来实现的。在 IOC 容器内部其实是将第二个过程解析得到的 BeanDefinition 注入到一个 HashMap 容器中,IOC 容器就是通过这个 HashMap 来维护这些 BeanDefinition 的。在这里需要注意的一点是这个过程并没有完成依赖注入,依赖注册是发生在应用第一次调用 getBean() 向容器索要 Bean 时。当然我们可以通过设置预处理,即对某个 Bean 设置 lazyinit 属性,那么这个 Bean 的依赖注入就会在容器初始化的时候完成。
// 根据 Xml 配置文件创建 Resource 资源对象。ClassPathResource 是 Resource 接口的子类,
//bean.xml 文件中的内容是我们定义的 Bean 信息。
ClassPathResource resource = new ClassPathResource("bean.xml");
//创建一个 BeanFactory。DefaultListableBeanFactory 是 BeanFactory 的一个子类,BeanFactory //作为一个接口,其实它本身是不具有独立使用的功能的,而 DefaultListableBeanFactory 则是真正可以独立
//使用的 IOC 容器,它是整个 Spring IOC 的始祖,在后续会有专门的文章来分析它。
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//创建 XmlBeanDefinitionReader 读取器,用于载入 BeanDefinition 。
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//开启 Bean 的载入和注册进程,完成后的 Bean 放置在 IOC 容器中。
reader.loadBeanDefinitions(resource);

Resource 定位

  • Spring 为了解决资源定位的问题,提供了两个接口:Resource、ResourceLoader
    • 其中 Resource 接口是 Spring 统一资源的抽象接口
    • ResourceLoader 则是 Spring 资源加载的统一抽象。
      • 在上面那段代码中 new ClassPathResource("bean.xml") 为我们定义了资源
      • 那么 ResourceLoader 则是在什么时候初始化的呢?

看 XmlBeanDefinitionReader 构造方法:

直接调用父类 AbstractBeanDefinitionReader :

  • 核心在于设置 resourceLoader 这段,如果设置了 ResourceLoader 则用设置的,
  • 否则使用 PathMatchingResourcePatternResolver ,该类是一个集大成者的 ResourceLoader。

BeanDefinition 的载入和解析

reader.loadBeanDefinitions(resource); 开启 BeanDefinition 的解析过程。如下:

  • 而将 Resource 封装成 EncodedResource 主要是为了对 Resource 进行编码,保证内容读取的正确性

  • 从 encodedResource 源中获取 xml 的解析源,调用 doLoadBeanDefinitions() 执行具体的解析过程
  • 在该方法中主要做两件事:
    • 1、根据 xml 解析源获取相应的 Document 对象,
    • 2、调用 registerBeanDefinitions() 开启 BeanDefinition 的解析注册过程。

转换为 Document 对象

  • 调用 doLoadDocument() 会将 Bean 定义的资源转换为 Document 对象。
    • loadDocument() 方法接受五个参数:

      • inputSource:加载 Document 的 Resource 源

      • entityResolver:解析文件的解析器

      • errorHandler:处理加载 Document 对象的过程的错误

      • validationMode:验证模式

      • namespaceAware:命名空间支持。如果要提供对 XML 名称空间的支持,则为true

  • 就已经将定义的 Bean 资源文件,载入并转换为 Document 对象了,那么下一步就是如何将其解析为 Spring IOC 管理的 Bean 对象并将其注册到容器中。
  • 这个过程有方法 registerBeanDefinitions() 实现。如下:

  • 首先创建 BeanDefinition 的解析器 BeanDefinitionDocumentReader,
  • 然后调用 documentReader.registerBeanDefinitions() 开启解析过程,这里使用的是委派模式,具体的实现由子类 DefaultBeanDefinitionDocumentReader 完成。

对 Document 对象的解析

  • 从 Document 对象中获取根元素 root,然后调用 doRegisterBeanDefinitions() 开启真正的解析过程

  • preProcessXml()postProcessXml() 为前置、后置增强处理,目前 Spring 中都是空实现,
  •  parseBeanDefinitions() 是对根元素 root 的解析注册过程

  • 迭代 root 元素的所有子节点,对其进行判断,若节点为默认命名空间,则ID调用 parseDefaultElement() 开启默认标签的解析注册过程,
  • 否则调用 parseCustomElement() 开启自定义标签的解析注册过程。

标签解析

  • 若定义的元素节点使用的是 Spring 默认命名空间,则调用 parseDefaultElement() 进行默认标签解析,如下:

  • 对四大标签:import、alias、bean、beans 进行解析,其中 bean 标签的解析为核心工作

对于默认标签则由 parseCustomElement() 负责解析。

注册 BeanDefinition

  • 调用 BeanDefinitionReaderUtils.registerBeanDefinition() 注册,
  • 其实这里面也是调用 BeanDefinitionRegistry 的 registerBeanDefinition()来注册 BeanDefinition ,
  • 不过最终的实现是在 DefaultListableBeanFactory 中实现,如下:
  • 最核心的部分是这句 this.beanDefinitionMap.put(beanName, beanDefinition) ,
  • 所以注册过程也不是那么的高大上,就是利用一个 Map 的集合对象来存放,key 是 beanName,value 是 BeanDefinition。

 

© 著作权归作者所有

共有 人打赏支持
Java搬砖工程师
粉丝 26
博文 257
码字总数 161825
作品 0
南京
程序员
私信 提问
【死磕 Spring】—– IOC 之 IOC 初始化总结

原文出自:http://cmsblogs.com 前面 13 篇博文从源码层次分析了 IOC 整个初始化过程,这篇就这些内容做一个总结将其连贯起来。 在前文提过,IOC 容器的初始化过程分为三步骤:Resource 定位...

chenssy
10/09
0
0
深入理解Spring源码(一)-IOC容器的定位,载入,注册

前言:Spring源码继承,嵌套层次非常多,读起来非常容易晕,小伙伴们在看文章的时候一定要跟着文章的思路自己去源码里点一点,看一看,并且多看几次。就会越来越清晰。下面开始正题 1.Spring...

Meet相识_bfa5
05/01
0
0
Spring MVC 原理探秘 - 容器的创建过程

1.简介 在上一篇文章中,我向大家介绍了 Spring MVC 是如何处理 HTTP 请求的。Spring MVC 可对外提供服务时,说明其已经处于了就绪状态。再次之前,Spring MVC 需要进行一系列的初始化操作。...

coolblog.xyz
07/03
0
0
那些年,我们一起追的Spring

学无止境,但仍需及时总结。 自去年开始写作以来,写了一些关于Spring的文章,今天将它们汇总起来,一方面方便大家阅读,另一方面,也是一次小的复盘总结。 IOC 首先是Spring的IOC,也就是控...

SexyCode
08/14
0
0
Spring IOC知识点一网打尽!

前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 单例模式你会几种写法? 工厂模式理解了没有? 在刷Spring书籍的时候花了点时间去学习了单例模式和工...

Java3y
05/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring应用学习——AOP

1. AOP 1. AOP:即面向切面编程,采用横向抽取机制,取代了传统的继承体系的重复代码问题,如下图所示,性能监控、日志记录等代码围绕业务逻辑代码,而这部分代码是一个高度重复的代码,也就...

江左煤郎
今天
3
0
eclipse的版本

Eclipse各版本代号一览表 Eclipse的设计思想是:一切皆插件。Eclipse核心很小,其它所有功能都以插件的形式附加于Eclipse核心之上。 Eclipse基本内核包括:图形API(SWT/Jface),Java开发环...

mdoo
今天
1
0
SpringBoot源码:启动过程分析(一)

本文主要分析 SpringBoot 的启动过程。 SpringBoot的版本为:2.1.0 release,最新版本。 一.时序图 还是老套路,先把分析过程的时序图摆出来:时序图-SpringBoot2.10启动分析 二.源码分析 首...

Jacktanger
今天
4
0
小白带你认识netty(二)之netty服务端启动(上)

上一章 中的标准netty启动代码中,ServerBootstrap到底是如何启动的呢?这一章我们来瞅下。 server.group(bossGroup, workGroup);server.channel(NioServerSocketChannel.class).optio...

天空小小
今天
3
0
聊聊storm trident batch的分流与聚合

序 本文主要研究一下storm trident batch的分流与聚合 实例 TridentTopology topology = new TridentTopology(); topology.newStream("spout1", spout) .p......

go4it
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部