《系列一》-- 3、XmlBeanFactory 对xml文件读取

系列,xmlbeanfactory,xml,文件,读取 · 浏览次数 : 41

小编点评

**阅读之前要注意的内容:** 1. 这篇文章是关于 Spring 源码 5.x 版本的流水账式的代码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。 2. 文章主要介绍了如何解析 Spring 中的 xml 配置文件,包括如何读取xml文件的内容、格式校验以及如何从xml文件中获取bean定义信息。 3. 文章以清晰的步骤和图示的方式,解释了如何从xml文件中读取bean定义信息并将其注入到Spring中的bean中。 4. 文章还介绍了如何配置xml校验模式以及如何使用默认的和自定义的命名空间。

正文




阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于 spring 源码 5.x 版本。



Spring源码阅读系列--全局目录.md



引子

1、容器最基本使用.md

系列1 - bean 标签解析:

2、XmlBeanFactory 的类图介绍.md

3、XmlBeanFactory 对xml文件读取.md

4、xml配置文件解析之【默认】命名空间【标签】的解析.md

5、xml配置文件解析之【自定义】命名空间【标签】的解析.md

系列2 - bean 获取: getBean() 做了什么

前言

还是老规矩,先一句话概括本文干了啥:

  • 配置 Bean的 xml 文件读取
  • xml 文件内容、格式校验: DTD / XSD
  • 将 xml 配置的内容,解析为 BeanDefinition,注册到 "Bean 工厂" XmlBeanfactory 中

1 跟随 XmlBeanFactory 的构造方法逐步跳转:

2 parentFactory 的处理

因为入参给的是null,先忽略它。

super(parentFactory);

3 XmlBeanDefinitionReader

这里我们关注下,这里的 reader,它就是本文绝对的C位了,从名字就知道它干啥的了:

注意看 XmlBeanDefinitionReader 构造函数的入参,没错 XmlBeanFactory 被传进去了,不过这里被向上转型为:BeanDefinitionRegitry 接口类型了

由此可见,XmlBeanDefinitionReader 的解析结果,或者它的 后继者 的解析结果,最终肯定会注册到 XmlBeanFactory 上的。

不信走着瞧,后边一定能发现 某个地方在暗搓搓的调用 XmlBeanDefinitionReader.getRegistry() 方法,这时后你要知道 这里获取到对象,实质上就是我们的: XmlBeanFactory , 别问我为什么,你回过头去看类图就知道了。

4 从文件流读取内容

5 至关重要的两行代码

下图的两行代码,分别就是下边 [第6] 和 [第7] 章节要讲述的内容:

6 第一行做的事,就是前边提到的 xml 格式校验

6.1 识别 xml 文件的校验模式

下图做的事很好解释:

  • 1.如果 "Bean 工厂" 预先配置了校验模式,将覆盖xml 中配置的 dtd 或 xsd 文件

    • 在 XmlBeanFactory 的场景瞎, XmlBeanDefinitionReader 是 XmlBeanFactory 的成员变量。

      除了 XmlBeanFactory 别的地方同样也会使用 XmlBeanDefinitionReader,区别是 XmlBeanFactory 只是使用了默认的 xml 校验。

      如果我们反向跟踪瞎,谁调用过: setValidationMode() 方法,找到了下图中的:XmlWebApplicationContext ,这就说明在这个容器里,是支持动态设置xml校验模式的。

  • 2.如果 "Bean工厂-BeanFactory" 没有预置 xml 校验模式,就会去扫描 xml 配置文件,读取其中配置的是:dtd 或者 xsd文件

    • 这里会逐行读取xml 文件,从中提取xml 的校验方式

看下图,就是个很鲜活的例子,这里使用的是 dtd

6.2 校验模式识别后,就是加载配置

还是第五节的第一个图,我们进入 loadDocument 方法一探究竟:

this.documentLoader.loadDocument(xx,xxx,xx....)

实际上 documentLoader 这里是声明的接口,我们可以全局搜索一下,找到了它的唯一实现类:

最后进入到 loadDocument 方法

  • 就是根据检验模式校验文件
  • 校验通过后返回一个Document 对象,其实常规的 Xml 读取应该也是类似的套路。

7 第二行在校验通过后正式开始解析

直到第6章为止,通过重重校验后,拿到了一个由原始 xml 配置文件封装的 Document 对象

本节要做的事就是从该 Document对象中,读取BeanDefinition 【Bean定义/配置信息】

老三样,根据接口定位它的实现类:

然后我们来到了此行的终点:

我们看这句代码,它把 xml 文档传进去了,也传了委托处理 "BeanDefinitioin" 的对象:delegate

parseBeanDefinitions(root, this.delegate);

我们还可以稍微再进去一丢丢:

下图中,我添加的注释里,提到了两个关键词:

  • 默认命名空间

    • 指的是 spring 官方支持的 xml 配置文件的元素和标签
  • 自定义命名空间

    • 属于开发者个人对spring的个性化魔改。

再往下就是 具体 xml 标签、元素的识别和解析了。暂时不用去深究它,到这里我们需要明白的是:

  • parseBeanDefinitions(root, this.delegate)方法会完成 xml 解析
  • 最终的解析结果将会被: XmlBeanFactory (BeanDefinitionRegistry接口) 持有
  • 当从 XmlBeanFactory 调用 getBean() 时,就会从 BeanDefinitionRegistry接口管理的配置信息中,获取到相关类的信息
  • 最后利用类信息 + 反射技术,得到 类的实例对象,并且,该对象(Bean) 将会被 XmlBeanFactory (BeanFactory接口) 管理

8 后话

至于为什么我在第七章末尾说:xml最终的解析结果被 XmlBeanFactory (BeanDefinitionRegistry接口) 持有呢?

我们可以追溯下,XmlBeanFactory 在这个解析过程中,是怎么被逐步传递的。

8.1 XmlBeanFactory 的第一次传递

前文提到过,在 XmlBeanFactory 类中初始化 reader 时调用了 XmlBeanDefinitionReader 的构造函数,这里已经把 XmlBeanFactory 自身作为参数传递进去了。

参数名为:

  • registry

8.2 XmlBeanFactory 的第二次传递

这个引用关系传递得非常隐蔽:
回过头去看 [第7章] 的第一个图,Document 的处理被委托给了一个别的类:

// 这里 documentReader 还特么是个局部变量 
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();

从这里可以得知,xml解析方法的调用链,已经离开 XmlBeanFactory.reader[XmlBeanDefinitionReader] 内部了;

只看这句代码,你会觉得 documentReader 只是一个在方法内部定义的局部变量,它解析完结果不就丢了么?

真的是这样吗,看下图的 createReaderContext 方法标注的内容:

没想到吧在这里, XmlBeanFactory.reader[XmlBeanDefinitionReader] 又一次被传下去了,所以引用链还是没断的,只是在不容易发现的地方,在默默的延续。

XmlBeanDefinitionReader.createReaderContext() 方法内,创建 XmlReaderContext 实例对象时,传递的 "this" 的 成员变量 registry 就是我们的 XmlBeanFactory 的对象实例。

xml解析方法的调用链,虽然已经离开 XmlBeanFactory.reader[XmlBeanDefinitionReader],去到了 BeanDefinitionDocumentReader 内部,但是 XmlBeanFactory 也随着 BeanDefinitionDocumentReader 也悄悄的跟着去了。

8.3 XmlBeanFactory 的第三次传递

到本文 [第7章] 的最后,Xml 的解析又被委托给了:

  • BeanDefinitionParserDelegate

通过下边的两个图我们看看 BeanDefinitionParserDelegate 创建的时候都发生了什么:

先说说 parentDelegate = this.delegate,在我们当前场景下没有做出任何额外的配置动作,这里获取到的会是个空值:null

接着关注下: createDelegate() 方法的第一个参数:

  • getReaderContext()

它获取到的,就是上一节提到的,用 XmlBeanDefinitionReader 封装的 XmlReaderContext 对象。

在这里,可以认为, XmlBeanFactory 借道 XmlReaderContext 又一次悄悄的潜入到了, Xml 标签/元素 解析的 "代理类" 内部了。

XmlBeanFactory 真的是干特务的一把好手啊。

悄悄的进村,打枪的不要,哈哈。


最后的最后,当我们解析完成 xml 后要进行最终的注册时:需要经历如下的调用链才能拿到我们的:XmlBeanFactory 对象。


BeanDefinitionParserDelegate()
    .XmlReaderContext()
        .BeanDefinitionDocumentReader()
            .XmlBeanFactory()









下一篇文章将会花一定篇幅,介绍spring的 xml 配置文件中定义的元素、标签的读取。

与《系列一》-- 3、XmlBeanFactory 对xml文件读取相似的内容:

《系列一》-- 3、XmlBeanFactory 对xml文件读取

阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证。全系列文章基于 spring 源码 5.x 版本。 Spring源码阅读系列--全局目录.md 引子 1、容器最基本使用.md 系列1 - bean 标签解析: 2、XmlBeanFactory

[转帖]Django系列3-Django常用命令

文章目录 一. Django常用命令概述二. Django常用命令实例2.1 help命令2.2 version2.3 check2.4 startproject2.5 startapp2.6 runserver2.7 shell2.8 migrations2.8.1 makemigrations2

Rancher 系列文章-RHEL7.8 离线有代理条件下安装单节点 Rancher

一 基础信息 1.1 前提 本次安装的为 20220129 最新版:Rancher v2.6.3 VM 版本为 RHEL 7.8, 7.9 或 8.2, 8.3, 8.4(Rancher 官网要求) VM YUM 仓库:已配置对应版本的 RHEL 和 EPEL YUM 仓库 VM 提供 root 权

K3S 系列文章-RHEL7.8 离线有代理条件下安装 K3S

一 基础信息 1.1 前提 本次安装的为 k3s 1.21.7+k3s1 VM 版本为 RHEL 7.8, 7.9 或 8.2, 8.3, 8.4(K3s 官网要求) VM YUM 仓库:已配置对应版本的 RHEL 和 EPEL YUM 仓库 VM 提供 root 权限 已配置 ntp(防止因为时间

机器学习算法(一):1. numpy从零实现线性回归

系列文章目录 机器学习算法(一):1. numpy从零实现线性回归 机器学习算法(一):2. 线性回归之多项式回归(特征选取) @目录系列文章目录前言一、理论介绍二、代码实现1、导入库2、准备数据集3、定义预测函数(predict)4 代价(损失)函数5 计算参数梯度6 批量梯度下降7 训练8 可视

保姆教程系列:小白也能看懂的 Linux 挂载磁盘实操

!!!是的没错,胖友们,保姆教程系列又更新了!!! @目录前言简介一、磁盘分区二、文件系统三、实际操作1. 使用lsblk命令查看新加入的磁盘信息2. 使用fdisk或者cfdisk分区新磁盘,并将分区标记为Linux文件系统类型(83)3. 格式化新分区,使用mkfs命令4. 创建挂载目录,使用m

[转帖]Centos下使用containerd管理容器:5分钟从docker转型到containerd

https://www.cnblogs.com/renshengdezheli/p/16684175.html 目录 一.系统环境 二.前言 三.containerd 四.部署containerd 4.1 安装containerd 4.2 containerd配置文件 4.3 配置container

面试题:Linux 系统基础提问 (一)

Linux系统中如何管理用户和组? Linux系统中用户和组的管理通常包括以下几个方面: 1、创建用户和组: 使用useradd和groupadd命令创建新用户和新组。 2、修改用户和组信息: 使用usermod和groupmod命令来修改用户和组的信息。 3、删除用户和组: 使用userdel和g

回测收益170%的趋势交易策略——《基于模糊理论的趋势交易-王立新》论文精读

这篇论文2014年发布在SCI一区,共3篇,作者是师承模糊集之父Zadeh的王立新教授(西安交通大学),论文的贡献在于把金融领域模糊的表达转变为模糊集(fuzzy sets)和隶属函数(membership),先看回测展示: 图中上图绿线表示买入并持有,红线表示卖出。下图是系数值,绿色代表买方力量值

[转帖]openGauss单机部署

作者:可达 openGauss单机部署 一、安装环境 1.操作系统:虚拟机VMware、CentOS7.9 2.环境设置: (1)虚拟机内存3G、磁盘100G (2)系统版本修改 一开始使用了centos8,无法安装,因此降低版本,选用7.9后依然存在一些问题,因此修改/etc/redhat-rel