【系列目录】
Mybatis源码阅读之一——工厂模式与SqlSessionFactory
Mybatis源码阅读之二——模板方法模式与Executor
Mybatis源码阅读之三——JDBC解析与Mybatis封装
Mybatis源码阅读之四——装饰器模式与Mybatis中的各种Cache
【本文目录】
系列的前几篇中,我们从Mybatis使用的角度一步步深入到源码,今天从另一个角度,来看一下Mybatis资源的加载流程。
Mybatis中,Sql的模板编写有两种方式,一个是xml,另一种是注解。其中xml方式是最早出现的,也是支持最全面的。
一. XML
可扩展标记语言,标准通用标记语言的子集,简称XML。是一种用于标记电子文件使其具有结构性的标记语言。
从概念中我们能获取几个关键字:
- 标记语言
什么是标记语言?通俗的理解,就是给一堆五结构化的数据以结构。比如HTML,HTML提供了各种各样的标签,用于协议一个结构框架。 - 可扩展
标记语言如HTML是不可扩展的,他的标签固定,除非升级HTML版本否则无法增加其他的标签,这就是不可扩展,而XML则解决了这一问题,是可扩展的。
XML可扩展的关键,就在于它有一个定义自己结构的“元标签定义”,那就是DTD。
DTD
DTD提供了一系列合法的元素来定义文档的结构,如下图所示,是Mybatis定义的DTD文件,用于定义Mapper的xml中的标签语法。
XML语法
XML文档呈现树状结构,从root节点开始,一层层的子节点填充在里面,这其中,有一些语法规则:
- 有且只有一个根元素
- Xml文档声明必须放在文档第一行
- 所有标签必须成对出现
- Xml标签严格区分大小写
- XML必须正确嵌套
- XML中的属性值必须加引号
- XML中,一些特殊字符需要使用实体,比如小于号要使用<来代替。
二. JAVA官方的xml解析-DOM
JAVA官方提供了对xml解析的方法,在rt包的java.xml下:
使用案例
下面使用java的xml包来解析一个我们自定义的xml:
-
xml文件
-
解析代码
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
public class A2 {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
InputStream input = A2.class.getResourceAsStream("./mybatis-config.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(input);
printNode(doc.getFirstChild(),0);
}
static void printNode(Node n, int indent) {
for (int i = 0; i < indent; i++) {
System.out.print(' ');
}
switch (n.getNodeType()) {
case Node.DOCUMENT_NODE: // Document节点
System.out.println("Document: " + n.getNodeName());
break;
case Node.ELEMENT_NODE: // 元素节点
System.out.println("Element: " + n.getNodeName());
break;
case Node.TEXT_NODE: // 文本
System.out.println("Text: " + n.getNodeName() + " = " + n.getNodeValue());
break;
case Node.ATTRIBUTE_NODE: // 属性
System.out.println("Attr: " + n.getNodeName() + " = " + n.getNodeValue());
break;
default: // 其他
System.out.println("NodeType: " + n.getNodeType() + ", NodeName: " + n.getNodeName());
}
for (Node child = n.getFirstChild(); child != null; child = child.getNextSibling()) {
printNode(child, indent + 1);
}
}
}
- 展示结果
由上面的案例我们能够认识到xml是一个树形结构的数据,因此我们需要使用循环/嵌套/递归等方式来解析,那么有没有另外一种手段,能够更简洁直接的从这个树形结构中获取实际数据呢?
XPath
XPath 是一门在 XML 文档中查找信息的语言。
- XPath基本语法
表达符 | 含义 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取(取子节点)。 |
// | 从匹配选择的当前节点选择文 档中的节点,而不考虑它们的 位置(取子孙节点)。 |
. | 选取当前节点。 |
… | 选取当前节点的父节点。 |
@ | 选取属性。 |
-
语法示例(以上述demo为案例)
选取Mybatis下的title标签:/mybatis/title
选取mybatis下的names中的第一个name标签:/mybatis/names/name[1] -
java实现
只需要在上述demo中增加java.xml提供的Xpath实例,即可使用Xpath功能。
三. Mybatis的xml解析
回顾之前我们使用Mybatis的方式Mybatis源码阅读之一——工厂模式与SqlSessionFactory,在SqlSessionFactory的各种重载的构建方法中,都会走到这么一个逻辑中。
解析初始化配置文件
- 构建XMLConfigBuilder
- XMLConfigBuilder构造
- XPathParser构造
这里只做了两件事情:
- 生成一个xpath解析器
- 生成一个mybatis配置文件的document对象。
- 回到SqlSessionFactoryBuilder.build中,得到XMLConfigBuilder对象后会进行parse操作。
- XMLConfigBuilder.parse
- parser.evalNode("/configuration")
解析mybatis配置文件顶层节点,将java.xml解析器得到的Node结果进行封装,得到自定义的XNode对象。
- 回到XMLConfigBuilder.parseConfiguration
获取到根节点后,解析里面的各种配置(包括数据源配置):
其中mapperElement方法则会涉及到我们自己的mapper xml文件解析。 - XMLConfigBuilder.mapperElement
我们有时因为Mapper和Mapper xml对应不上导致的异常也会在(初始化过程的)这个地方报出来。
到这里,也就是Mybatis使用xml的大致过程,DefaultSqlSessionFactory的初始化过程已经讲解完毕。
在mybatis配置解析中有一个核心配置——datasource:
接下来,我们分析一下Mybatis的数据库连接池实现以及同时下热门三方连接池的比较。
欢迎关注微信公众号 【JAVA技术分享官】,公众号首发,持续输出原创高质量JAVA开发者知识点