程序员高级码农II 发表于 2021-1-5 07:28:00

mybatis源码详解底子功能包源码阅读:parsing包

parsing包背景知识

XML文件
可扩展标志语言(eXtensible Markup Language,XML)是一种标志语言。所谓的标志是指计算机所能理解的信息符号,通过标志可以实现软件开辟者与计算机之间的信息沟通。常见的 HTML便是一种标志语言,不外 HTML语言中的标签(如“<h1> </h1>”“<img\>”等)都是固定的,是不可扩展的。XML则可以由开辟职员自由扩展定义。
XML可扩展的一个重要体现就是 XML文档的结构是可以自由定义的。定义 XML文档可以使用 DTD(Document Type Definition,文档类型定义),也可以使用 XML Schema。不外在介绍 DTD和 XML Schema之前,我们先来相识 XML文档的结构。
XML文档中包罗浩繁的节点。节点分为以下几类:元素节点、属性节点、文本节点、文档节点等。在实际指代中,可以省略“节点”二字,也可以将以上各类统称为“节点”。
以代码11-1给出的 XML文档为例。文档第一行为 XML声明,它声明了 XML的版本是 1.0,使用的编码是 UTF-8。XML中从一个标签开始(含)到一个标签结束(含)的部分叫作元素节点,例如,从第一个“<user>”到第一个“</user>”之间的部分就是一个 user元素节点。元素节点可以有属性节点,如“type="student"”。元素节点可以包罗其他元素节点,例如,user元素包罗了 id、name、school这三个元素节点。元素节点中也可以有文本节点,例如,第一个 name元素节点中就包罗了文本节点,值为“易哥”。
【代码11-1】
https://p1.pstatp.com/large/pgc-image/397c059db8594cf79bb130b6b6b32627
代码11-1中,members元素位于顶层,因此是根元素。每一个 XML文档都必须有一个根元素。
XML文档实际上表述了一棵树。图11-1就展示了代码11-1的结构树。
https://p1.pstatp.com/large/pgc-image/85ad99e4dc884f8cafc61db875a3d77d图11-1 结构树
在一个 XML文档中,可以存在什么元素及每个元素是怎样的,这些是由 XML文档的定义文件来进行形貌的,如 DTD(此类文件的后缀名为dtd)或者 XML Schema(此类文件的后缀名为 xsd)。
以 XML Schema文档为例,我们可以使用代码11-2来定义代码11-1中展示的 XML片段。
【代码11-2】
https://p1.pstatp.com/large/pgc-image/c6e7a662362d44f8967dfc40ebd8802e
而使用 DTD,则可以使用代码11-3来定义代码11-1中展示的 XML片段。
【代码11-3】
https://p1.pstatp.com/large/pgc-image/cc4062efaed04ce7bfba00557fa0429b
代码11-3所示的 DOCTYPE声明中,members是根节点名称,“[]”中为节点的限制条件。而且,DTD也支持使用外部 DTD文档来定义 XML文档,例如,在 MyBatis的配置文档开头可以看到如代码11-4所示的片段就引用了外部的 DTD文档。
【代码11-4】
https://p1.pstatp.com/large/pgc-image/c966e8e0f4b340aeb52ecdf94289f21e
在代码11-4所示的 DOCTYPE声明中,各个项目的含义如下。
· configuration:表示当前 XML文档的根节点为 configuration。
· PUBLIC:表示当前 XML文档接纳的是公共的 DTD。
·-//mybatis.org//DTD Config 3.0//EN:表示 DTD文档的信息。
--:表示优劣 ISO组织;
-mybatis.org:表示组织名称 mybatis.org;
-DTD Config 3.0:表示文本形貌,包括版本号;-EN:表示 DTD文档是英文。
· http://mybatis.org/dtd/mybatis-3-config.dtd:表示文档的下载地址。
XPath
在上一节我们已经说明了 XML表述一种树状结构,并通过图11-1给出了代码11-1中XML片段的结构树。而 XPath(XML Path Language,XML路径语言)作为一种小型的查询语言能够根据 XML结构树在树中寻找节点。
XPath定义了一组语法,能够从结构树中筛选出满意要求的节点。
如果读者对 CSS选择器或 jQuery选择器比较熟悉的话,那把握 XPath的语法还优劣常简单的,因为这些选择器的语法思路是相通的。
我们可以通过表11-1中所示的例子来简单相识 XPath的语法。
https://p1.pstatp.com/large/pgc-image/ec837e4a325b4a6380aae5983545d73d表11-1 XPath语法示例
javax.xml.xpath包提供了强大的 XPath解析功能,可以基于它实现 XML的解析。例如,可以通过代码11-5解析代码11-1给出的 XML片段,得到图11-2所示的程序运行效果。
【代码11-5】
https://p9.pstatp.com/large/pgc-image/86386831f8554da5a710feea7e53242e
https://p1.pstatp.com/large/pgc-image/2a17f71da06f4ee3aae5cfbbefbdd7cb


https://p1.pstatp.com/large/pgc-image/1ef174f71cfe4cc4bfaac18928cc92f5图11-2 程序运行效果
在代码11-5中,通过“/members/user”定位出了一个 user元素,该元素满意以下条件。
· 该元素是根元素 members的直接子元素;
· 该元素含有 id子元素,且 id子元素值为 1。
XML解析

MyBatis的配置文件与映射文件均是 XML文件,因此解析并读取 XML文档中的内容是 MyBatis展开后续工作的基础。
MyBatis中的 parsing包就是用来进行 XML文件解析的包。在解析XML文件的过程中,XPathParser类与 XNode类是两个最为关键的类,图11-3给出了这两个类主要关系的类图。
https://p9.pstatp.com/large/pgc-image/403237644a554b1a873dce3672b0a811图11-3 XPathParser类与XNode类主要关系的类图
通过图11-3 可以看出,XPathParser 类中封装了“javax.xml.xpath.XPath”类的对象。而通过 11.1.2节的介绍我们也知道 XPath对象是 XML解析的利器,因此 XPathParser类便具有了 XML解析的能力。
代码11-6给出了 XPathParser类的带注释的属性。
【代码11-6】
https://p3.pstatp.com/large/pgc-image/2460a19348874fb2a87bb48fd2ed399c
有必要说明一下,上述“private Properties variables”属性存储的内容就是 MyBatis配置文件中 properties 节点的信息。properties 节点会在解析配置文件的最开始就被解析,然后相关信息会被放入“private Properties variables”属性并在解析后续节点时发挥作用,在11.3节我们会详细介绍这一点。
XPathParser存在多个重载的构造方法,它们均根据传入的参数完成属性的初始化并构造出 XML文档对应的 Document对象。除去构造方法外,便是大量提供 XML文档中节点解析功能的“eval*”方法,这些方法最后都调用了如代码11-7所示的 evaluate方法。
【代码11-7】
https://p1.pstatp.com/large/pgc-image/092b0cb03e4d403a8eb75fb5c555c614
在 evaluate方法中,使用“javax.xml.xpath.XPath”对象进行了节点解析。因此,整个XPathParser类本质就是对“javax.xml.xpath.XPath”的封装和调用,可以把 XPathParser类看作 javax.xml.xpath.XPath类的包装类。
同样,可以将 parsing 包中的 XNode 类看作 org.w3c.dom.Node类的包装类。org.w3c.dom.Node类是用来表示 DOM中节点的类,而 XNode类只是在 org.w3c.dom.Node类的基础上提取和补充了几个属性。代码11-8给出了 XNode对象的属性。
【代码11-8】
https://p9.pstatp.com/large/pgc-image/b9a3bab790f14ed5a48580325ddda2bf
XNode对象的上述属性中,name、body、attributes这三个属性是从“org.w3c.dom.Node”对象中提取出来的,而 variables、xpathParser这两个属性则是额外补充进来的。
我们知道 XPathParser类具有解析 XML节点的能力,也就是说,XNode类中封装了自身的解析器。在一个类中封装自己的解析器,这是一种非常常见的做法,云云一来这个类不必要外界的资助便可以解析自身,即获得了自解析能力。
大家大概有过这样的经历:由于新安装的计算机上没有解压软件,于是从网络或者朋侪那边得到了一份解压软件。可是,拿到手的解压软件安装包却是一个压缩文件。尚未安装解压软件的你必然没法打开压缩文件获得安装包。而自解压文件(SelF-eXtracting,SFX)能够资助你摆脱这个逆境。自解析类也有雷同的优点,它减少了对外部类的依靠,具有更高的内聚性,也更为易用。
正是得益于 XNode类的自解析特性,它本身提供了一些“eval*”方法,从而能够解析自身节点内的信息。
文档解析中的变量更换

我们在 11.2节曾提及,MyBatis配置文件中 properties节点会在解析配置文件的最开始就被解析,并在解析后续节点时发挥作用。可是怎样才气让这些信息在 XML 文件的解析中发挥作用呢?
回到 XPathParser类,其“evalString(Object,String)”方法如代码11-9所示。
【代码11-9】
https://p3.pstatp.com/large/pgc-image/1b49260204ac4814a303b21f67b72e43
https://p3.pstatp.com/large/pgc-image/37c84a25cdda458db0a0b08e1f88d7af
我们发现在解析字符串时,通过“PropertyParser.parse”方法对解析出来的效果进行了进一步处理。而这一步处理中,properties节点的信息便发挥了作用。
PropertyParser类是属性解析器,与之关系密切的几个类的类图如图11-4所示。
https://p1.pstatp.com/large/pgc-image/73b41626ecce41ea80acb20a457dd619图11-4 PropertyParser及其相关类的类图
下面以 GenericTokenParser类为入口阅读图11-4所示的几个类。GenericTokenParser类是通用的占位符解析器,共有三个属性,相关注释如代码11-10所示。
【代码11-10】
https://p3.pstatp.com/large/pgc-image/141071839c414694823e545a5acb0fb8
GenericTokenParser 类中有唯一的一个 parse 方法,该方法主要完成占位符的定位工作,然后把占位符的更换工作交给与其关联的 TokenHandler 处理。我们通过一个例子对parse方法的功能进行介绍。假设“openToken=#{”“closeToken=}”,向 GenericTokenParser中的 parse方法传入的参数为“jdbc:mysql://127.0.0.1:3306/${dbname}?serverTimezone=UTC”,则 parse方法会将被“#{”和“}”包围的 dbname 字符串解析出来,作为输入参数传入 handler 中的handleToken方法,然后用 handleToken方法的返回值更换“${dbname}”字符串。
GenericTokenParser提供的占位符定位功能应用非常广泛,而不仅仅局限在 XML解析中,毕竟它的名称是“通用的”占位符解析器。SQL语句的解析也离不开它的资助。SQL语句中使用“#{}”或“${}”来设置的占位符也是依靠 GenericTokenParser 来完成解析的,流程与本节介绍的一样。
TokenHandler 是一个接口,如代码11-11 所示,它只定义了一个抽象方法handleToken。handleToken 方法要求输入一个字符串,然后返回一个字符串。例如,可以输入一个变量的名称,然后返回该变量的值。
【代码11-11】
https://p3.pstatp.com/large/pgc-image/af42e734d0944d608e0f65aa62bfeb7f
PropertyParser类的内部类 VariableTokenHandler便继续了该接口。代码11-12展示了VariableTokenHandler类的属性。
【代码11-12】
https://p1.pstatp.com/large/pgc-image/a0484ff1a73a4eec9bc1fa3694e0e332
相识了 VariableTokenHandler类的属性后,再阅读其 handleToken方法,如代码11-13所示。向 handleToken 方法中传入输入参数后,该方法会以输入参数为键尝试从 variables属性中寻找对应的值返回。在这个由键寻值的过程中还可以支持默认值。
【代码11-13】
https://p3.pstatp.com/large/pgc-image/31c5428d317d48a3b06fcfc0f273d3fe
https://p3.pstatp.com/large/pgc-image/6ef0ede106a4449b983fc678db381b0f
最后再看 PropertyParser中的静态方法 parse,如代码11-14所示。它做了以下几个工作将 GenericTokenParser提供的占位符定位功能和 TokenHandler提供的字符串更换功能串接在了一起。
· 创建一个 VariableTokenHandler对象(TokenHandler接口子类的对象)。该对象能够从一个 Properties对象(这里传入的是 properties节点信息)中根据键索引一个值。
· 创建了一个属性解析器。只要设置了该属性解析器要匹配的模式,它就能将指定模式的属性值定位出来,然后将其更换为 TokenHandler接口中 handleToken方法的返回值。
【代码11-14】
https://p9.pstatp.com/large/pgc-image/38f9a6c6fa3e4ed2afcde315e36dd390
这样一来,只要在 XML文件中使用“${”和“}”包围一个变量名,则该变量名就会被更换成 properties节点中对应的值。
本文给大家讲解的内容是通用源码阅读指导mybatis源码详解,基础功能包源码阅读: parsing包


[*]下篇文章给大家讲解的是通用源码阅读指导mybatis源码详解配置解析包源码阅读: 配置解析概述;
[*]觉得文章不错的朋侪可以转发此文关注小编;
[*]感谢大家的支持!

吴凡86 发表于 2021-1-6 01:54:02

转发了
页: [1]
查看完整版本: mybatis源码详解底子功能包源码阅读:parsing包