3、XmlBeanFactory 对xml文件读取
引子
系列1 - bean 标签解析:
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文件读取的更多相关文章
- php xml 文件读取 XMLReader
php xml 文件读取 <?php /** $xmlString = '<xml> <persons count="10"> <person ...
- javascript读取xml文件读取节点数据的例子
分享下用javascript读取xml文件读取节点数据方法. 读取的节点数据,还有一种情况是读取节点属性数据. <head> <title></title> < ...
- xml文件读取到数据库
xml文件读取到数据库 第一步,导包 c3p0,dom4j,jaxen,MySQL-connector 第二步 xml文件,config文件 第三步 javabean 第四步 c3p0的工具类 ...
- XML文件读取工具类
/// <summary> /// Author: jiangxiaoqiang /// </summary> public class XmlReader { //===== ...
- Xml 文件读取
.NET 读取Xml文件,用到XmlDocument类. 1.要获取文档的根: DocumentElement. 2.Attributes :获取 XmlAttributeCollection 包含此 ...
- C# XML文件读取
using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; usin ...
- 【U1结业机试题】新闻内容管理系统:解析XML文件读取Html模版生成网页文件
一.作业要求: 1.在xml文件中创建新闻节点news,包含标题.作者.日期.正文等信息 2.创建HTML模板文件 3.读取xml中所有新闻信息,并使用新闻信息替换模板文件中占位符,从而为每一条新闻生 ...
- 【Selenium + Python】之 Excel、CSV、XML文件读取数据并运用数据百度查询
目录 从Excel读取数据进行百度搜索 从CSV读取数据进行百度搜索 从XML读取数据进行登录操作 附:其他学习资料(<xml.etree.ElementTree模块>.<pytho ...
- java实现xml文件读取并保存到对象
首先浅聊一下解析xml的四种方式: 1.DOM方式:有缺点但是这个缺点却也是他的优点.下面详细介绍: 以树形的层次结构组织节点或信息片断集合,可以获得同一个文档中的多处不同数据.使用起来简单. 优点是 ...
- XML文件读取加上 Ajax请求
#region XML文件处理 XmlDocument doc = new XmlDocument(); XmlReaderSettings settings = new XmlReaderSetti ...
随机推荐
- MySQL核心知识
MySQL常用的命令 启动:net start mySql; 进入:mysql -u root -p/mysql -h localhost -u root -p databaseName; 列出数据库 ...
- api进阶Day3使用文件流对文件进行复制、使用块读写一组字节,使用byte数组提高读写的效率、返回当前时间。
使用文件流对文件进行复制: package io; import java.io.FileInputStream; import java.io.FileNotFoundException; impo ...
- php 验证身份证合法性
function checkIdcard($num = '') { $length = strlen($num); if ($length == 15) { //如果是15位身份证 //15位身份证没 ...
- Java工程结构 应用分层
(一) 应用分层 1. [推荐]图中默认上层依赖于下层,箭头关系表示可直接依赖,如:开放接口层可以依赖于 Web 层,也可以直接依赖于 Service 层,依此类推: • 开放接口层:可直接封装 Se ...
- Ubantu12.04安装及离线安装网卡驱动
一.用软通牒UltarISO写入硬盘映像,制作启动U盘 装机,ubantu安装很简单. 二.安装网卡驱动 1. 下载e1000e:https://downloadcenter.intel.com/De ...
- 转帖:GitBook 从懵逼到入门
是什么? 在我认识 GitBook 之前,我已经在使用 Git 了,毋容置疑,Git 是目前世界上最先进的分布式版本控制系统. 我认为 Git 不仅是程序员管理代码的工具,它的分布式协作方式同样适 ...
- MQ(创建MQ注意事项)
创建MQ队列管理器时,需要注意的事项包括以下几点: 1) 队列管理器的日志类型以及日志文件的大小和个数,要根据用户数据量的大小.各个队列上的消息总容量,来计算日志的总容量,以免在系统运行过程中出现日志 ...
- App测试之appium参数入门
Appium入门参数: platformName:平台名称,一般是Android或iOS: platformVersion:平台的版本号,可以使用以下命令: adb shell getprop ro. ...
- luffy项目全局配置
一:media文件夹配置 settings.dev下配置media文件夹,暴露资源 media_path=BASE_DIR.parentMEDIA_ROOT=Path(media_path).join ...
- modbus通讯协议详解
1.Modbus 协议简介 Modbus协议是一种已广泛应用于当今工业控制领域的通用通讯协议.通过此协议,控制器相互之间.或控制器经由网络(如以太网)可以和其它设备之间进行通信.Modbus协议使用 ...