最近闲来无事,看着一些源码类的书籍,只是光看,好像并不能给自己很好的益处,无法记下来,所以就有了这个Mybatis源码解析系列的博客。网上也有大量的源码解析,在此记录有两个原因,一是为了加深自己的印象,二来则是让广大读者朋友能及时纠正在下的一些理解的错误。如果各位发现有任何的错误,请留言指出,在此感激不尽。闲话不多说,这就开始我们的第一篇xml解析。
     首先,本博客系列的图、代码,大多来自《mybatis技术内幕》一书。

我们先来看看如图,mybatis的结构分层。

这一讲主要是对解析器模块一个简单分析。

那么就先由一个简单的Mybatis启动开始讲解吧。
也请大家下载mybatis源码(或者在https://github.com/mybatis/mybatis-3中找到对应的源码),本博客中的例子大部分来自己mybatis中的test包。我尽量减少在里面放置过多的源码。

https://github.com/mybatis/mybatis-3/blob/master/src/test/java/org/apache/ibatis/session/SqlSessionTest.java#L64

public static void setup() throws Exception {createBlogDataSource();final String resource = "org/apache/ibatis/builder/MapperConfig.xml";final Reader reader = Resources.getResourceAsReader(resource);sqlMapper = new SqlSessionFactoryBuilder().build(reader);}

在此处加载了mybatis的config文件,大家在mapperConfig.xml(https://github.com/mybatis/mybatis-3/blob/master/src/test/java/org/apache/ibatis/builder/MapperConfig.xml)中可以看到内容的。

在Build方法调用时会创建相应的xpath对象

https://github.com/mybatis/mybatis-3/blob/master/src/main/java/org/apache/ibatis/parsing/XPathParser.java#L229
createDocument方法中创建了xpath。

现在我们来说说xpath的API解析XML。

package org.apache.ibatis.test;import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
import org.apache.ibatis.io.Resources;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.*;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.Reader;public class XPathTest {private Document createDocument(InputSource inputSource) {boolean validation = true;EntityResolver entityResolver = new XMLMapperEntityResolver();// important: this must only be called AFTER common constructortry {DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();factory.setValidating(validation);factory.setNamespaceAware(false);factory.setIgnoringComments(true);factory.setIgnoringElementContentWhitespace(false);factory.setCoalescing(false);factory.setExpandEntityReferences(true);DocumentBuilder builder = factory.newDocumentBuilder();builder.setEntityResolver(entityResolver);builder.setErrorHandler(new ErrorHandler() {@Overridepublic void error(SAXParseException exception) throws SAXException {throw exception;}@Overridepublic void fatalError(SAXParseException exception) throws SAXException {throw exception;}@Overridepublic void warning(SAXParseException exception) throws SAXException {}});return builder.parse(inputSource);} catch (Exception e) {throw new BuilderException("Error creating document instance.  Cause: " + e, e);}}public static void main(String[] args) throws IOException, XPathExpressionException {final String resource = "org/apache/ibatis/builder/MapperConfig.xml";final Reader reader = Resources.getResourceAsReader(resource);XPathTest test = new XPathTest();Document document = test.createDocument(new InputSource(reader));XPathFactory factory = XPathFactory.newInstance();XPath xPath = factory.newXPath();Node nodes = (Node) xPath.evaluate("/configuration", document, XPathConstants.NODE);// 获取指定节点Node mappers = (Node) xPath.evaluate("mappers", nodes, XPathConstants.NODE);NodeList mapperList = mappers.getChildNodes();for(int i=0; i<mapperList.getLength(); i++){Node node = mapperList.item(i);if(node.getNodeType() == Node.ELEMENT_NODE) // 只让mapper节点进入,因为可能会有空的text节点System.out.println("get mapper source : " + getAttribute(node, "resource"));}}public static void parse(NodeList nodeList) {for(int i = 0; i < nodeList.getLength(); i++){NodeList childNodes = nodeList.item(i).getChildNodes();System.out.println("node name: " + nodeList.item(i).getNodeName());if(childNodes != null && childNodes.getLength() > 0)parse(childNodes);}}public static String getAttribute(Node node, String attributeName){NamedNodeMap nodeAttributes = node.getAttributes();for (int i= 0; i< nodeAttributes.getLength(); i ++){Node attribute = nodeAttributes.item(i);String name = attribute.getNodeName();String value = attribute.getNodeValue();if(attributeName.equalsIgnoreCase(name)){return value;}}return null;}
}

这是一个简单的xpath的解析xml的例子,与Mybatis中获取xml配置的解析差不多。
由此我们知道了xml的各节点是以该方式解析出来的。

现在我们来看看XPathParse类,该类就是封装了解析xml的api的。
XPathParse类中的字段说明:

private final Document document;  //就是我们上述XPathTest中的document对象
private boolean validation; //是否开启验证
private EntityResolver entityResolver;//用于加载本地的DTD文件(DTD是用来验证xml的合法性的)
private Properties variables; //用于记录mybatis-config.xml中的变量的键值对的,比如在xml中有${password}等变量时,会由该字段保留具体值。
private XPath xpath;// 与XPathTest中的xpath一致,用于解析xml

XNode对象是对于XPath中的获取的Node对象的一个封装,这里就不过多的讲解,各位可以去看该类的源码。

在XMLConfigBuilder类中的https://github.com/mybatis/mybatis-3/blob/master/src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java#L102

private void parseConfiguration(XNode root) {try {//issue #117 read properties firstpropertiesElement(root.evalNode("properties"));Properties settings = settingsAsProperties(root.evalNode("settings"));loadCustomVfs(settings);typeAliasesElement(root.evalNode("typeAliases"));pluginElement(root.evalNode("plugins"));objectFactoryElement(root.evalNode("objectFactory"));objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));reflectorFactoryElement(root.evalNode("reflectorFactory"));settingsElement(settings);// read it after objectFactory and objectWrapperFactory issue #631environmentsElement(root.evalNode("environments"));databaseIdProviderElement(root.evalNode("databaseIdProvider"));typeHandlerElement(root.evalNode("typeHandlers"));mapperElement(root.evalNode("mappers"));} catch (Exception e) {throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);}}

此方法中的root.evalNode中获取的XNode对象就是对XPath中的Node对象的一个封闭。

在此xml解析就大致完了,下一节应该会是反射相关的分析。
mybatis中大量用了反射来将Mapper接口中的方法参数与返回值做解析。

mybatis源码解析一 xml解析(解析器)相关推荐

  1. spring 源码分析(1)-xml文件解析

    我们在最开始接触spring的时候,看到不少书spring入门的例子如下 ApplicationContext atx = new ClassPathXmlApplicationContext(&qu ...

  2. Mybatis源码学习笔记之Mybatis二级缓存

    简介   Mybatis一级缓存是会话级的缓存,而二级缓存则是应用级别的缓存,默认关闭,二级缓存使用不慎可能会导致脏读. 开启方式(SpringBoot+Mybatis)   application. ...

  3. Mybatis源码介绍

    Mybatis源码体系介绍和配置文件解析源码剖析 Mybatis和传统JDBC的优势 Mybatis MyBatis是一个持久层的ORM框架,使用简单,学习成本较低.可以执行自己手写的 SQL语句,比 ...

  4. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

  5. mybatis源码阅读(三):mybatis初始化(下)mapper解析

    转载自 mybatis源码阅读(三):mybatis初始化(下)mapper解析 MyBatis 的真正强大在于它的映射语句,也是它的魔力所在.由于它的异常强大,映射器的 XML 文件就显得相对简单. ...

  6. Mybatis源码阅读(一):Mybatis初始化1.1 解析properties、settings

    *************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如 ...

  7. Mybatis源码阅读(一):Mybatis初始化1.3 —— 解析sql片段和sql节点

    *************************************优雅的分割线 ********************************** 分享一波:程序员赚外快-必看的巅峰干货 如 ...

  8. mybatis源码解析 - mapper代理对象的生成

    1.简单示例 先看一个简单纯粹的mybatis demo(不集成spring等其他框架),代码结构很简单,如下图: 完整代码地址:kingoe/boot-study:mapper层和我们平时说的dao ...

  9. mybatis源码解析(一)

    Mybatis 源码解析 (一) 一. ORM框架的作用 实际开发系统时,我们可通过JDBC完成多种数据库操作.这里以传统JDBC编程过程中的查询操作为例进行说明,其主要步骤如下: (1)注册数据库驱 ...

最新文章

  1. What do you need at home?
  2. 《C++代码设计与重用》——2.5 浅拷贝和深拷贝
  3. [译] NSCollectionView 入门教程
  4. 计算机桌面反应慢,Windows7电脑反应慢的解决方法
  5. 使用.Net图表开发工具JDash.Net添加组件
  6. sql server 更改端口之后的登入方式
  7. iOS GoldRaccoon第三方FTP文件夹下载失败原因
  8. [react] 有在项目中使用过Antd吗?说说它的好处
  9. 4.2 算法之数论 9274 beeline(python)
  10. 【Vue】—计算属性缓存VS方法以及侦听器的区别
  11. 计算机中丢失api-ms-win-crt-runtime-
  12. Java 2 实用教程 第一章 Java入门
  13. matlab pt站下载,SDPT3-4.0 求解最优化问题里的半定规 (SDP)经典并且十分有效的MATLAB程序包 244万源代码下载- www.pudn.com...
  14. 【Verilog基础】Verilog语法之标量(Scalar)与向量(Vector)
  15. java做一个鼠标连点_用C语言写一个鼠标连点器
  16. oracle -3233,ORA-3233 问题请教
  17. python 多继承 MRO
  18. [填坑]ubuntu 18.04+Windows 10双硬盘双系统修改默认启动顺序
  19. linux安装java.jdk环境
  20. Kotlin只是一个“网红,【面试必备】

热门文章

  1. [讨论]日本地震对中国软件服务外包行业的影响分析(宏观)
  2. 四, 创建数据库 CREATE DATABASE
  3. nrf51822 --- 外部中断 (按键)
  4. 无人驾驶1——自动驾驶硬件、软件概述
  5. 如何实现QSV转mp4呢?
  6. ubuntu 安装ninja
  7. 二次指数平滑法python程序
  8. 电脑装Windows+Ubuntu双系统,及后续调整硬盘和系统重装之后相关的引导问题
  9. 【报告分享】 2020年中国互联网医疗研究报告-36kr(附下载)
  10. Android如何设置为设备拥有者device-owner?