ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MyBatis初始化背后的"男人":解析器

2021-08-10 18:31:51  阅读:198  来源: 互联网

标签:解析器 Node String 初始化 Mybatis XPathConstants MyBatis new Reflector


Mybatis的初始化过程,就是组装Configuration的过程,在这个过程中,用到了一些工具,我列举了六个基本工具,如图所示。

image

图中展示了XMLConfigBuilder为了组装出Configuration对象所作出的努力,配备了至少六个基本工具。本文的重点,就是分析这六个工具的作用。

好怕怕啊,一下子分析六个那么多。别怕,每个工具不超过三行代码,你就会彻底明白(相信你自己)。


1. ObjectFactory

ObjectFactory objectFactory = new DefaultObjectFactory();
List<String> list = objectFactory.create(ArrayList.class);
list.add("apple");
System.out.println(list);
out put:
[apple]

ObjectFactory:反射创建对象工厂类。

2. Reflector、Invoker、ReflectorFactory

ObjectFactory objectFactory = new DefaultObjectFactory();

Student student = objectFactory.create(Student.class);

Reflector reflector = new Reflector(Student.class);
Invoker invoker = reflector.getSetInvoker("studId");
invoker.invoke(student, new Object[] { 20 });
invoker = reflector.getGetInvoker("studId");
System.out.println("studId=" + invoker.invoke(student, null));
output:
studId=20

代码逻辑:使用默认构造方法,反射创建一个Student对象,反射获得studId属性并赋值为20,System.out输出studId的属性值。

image

Invoker:反射类Class的Method、Field封装。

  • GetFieldInvoker等于从Field取值:field.get(obj)。

  • SetFieldInvoker等于给Field赋值:field.set(obj, args[0])。

  • MethodInvoker等于Method方法调用:method.invoke(obj, args)。

Reflector:保存一个类Class的反射Invoker信息集合。

DefaultReflectorFactory。

private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>();

缓存了多个类Class的反射器Reflector。(避免一个类,多次重复反射)

3. XPath、EntityResolver

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<settings>
		<setting name="defaultExecutorType" value="REUSE" />
		<setting name="defaultStatementTimeout" value="25000" />
	</settings>
	<mappers>
		<mapper resource="com/mybatis3/mappers/StudentMapper.xml" />
		<mapper resource="com/mybatis3/mappers/TeacherMapper.xml" />
	</mappers>
</configuration>

XPath,是针对Xml的“正则表达式”。

DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
builderFactory.setValidating(false);

DocumentBuilder builder = builderFactory.newDocumentBuilder();
// builder.setEntityResolver(new XMLMapperEntityResolver());
InputSource inputSource = new InputSource(Resources.getResourceAsStream("mybatis-config.xml"));

Document document = builder.parse(inputSource);

XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
String value = (String) xpath.evaluate("/configuration/settings/setting[@name='defaultStatementTimeout']/@value", document, XPathConstants.STRING);

System.out.println("defaultStatementTimeout=\"" + value + "\"");

Node node = (Node) xpath.evaluate("/configuration/mappers/mapper[1]", document, XPathConstants.NODE);
NamedNodeMap attributeNodes = node.getAttributes();
for (int i = 0; i < attributeNodes.getLength(); i++) {
	Node n = attributeNodes.item(i);
	System.out.println(n.getNodeName() + "=\"" + n.getNodeValue() + "\"");
}
output:
defaultStatementTimeout="25000"
resource="com/mybatis3/mappers/StudentMapper.xml"

/configuration/settings/setting[@name='defaultStatementTimeout']/@value

含义为:取configuration下面的settings下面的属性name值等于defaultStatementTimeout的setting节点的value属性值

/configuration/mappers/mapper[1]

含义为:取configuration下面的mappers下面的第1个mapper节点。

XPathConstants.STRING:说明获取的目标对象是一个String值。

XPathConstants.NODE:说明获取的目标对象是一个Node节点。

如果使用上面的代码运行XPath,程序将像蜗牛一样缓慢,问题原因是Xml内部的:

http://mybatis.org/dtd/mybatis-3-config.dtd

JDK会使用网络,去上面这个地址下载dtd文件,并解析,所以慢的像蜗牛(和网络环境有关)。

builder.setEntityResolver(new XMLMapperEntityResolver());

加入上面这句话,程序瞬间快如闪电。XMLMapperEntityResolver是Mybatis针对EntityResolver的实现类,它从本地环境去寻找dtd文件,而不是去网络上下载,所以,速度飞快。

Mybatis就是通过上面六个工具,去读取配置文件的。工具虽多,但架不住我三两句话把它描述清楚,避免长篇大论。


4. Mybatis中的XNode和XPathParser

上面有关XPath的例子,示例了解析一个String和一个Node。假设我想要解析Float类型和List集合,那么需要简单封装一下。

public Float evalFloat(Object root, String expression) {
    return Float.valueOf((String)(xpath.evaluate(expression, root, XPathConstants.STRING)));
}
public List<Node> evalNodes(Object root, String expression) {
      NodeList nodeList = (NodeList) xpath.evaluate(expression, document, XPathConstants.NODESET);
      List<Node> list = new ArrayList<Node>();
      for (int i = 0; i < nodeList.getLength(); i++) {
    	  Node n = nodeList.item(i);
    	  list.add(n);
      }
      return list;
}

除了Float和List,可能还有Integer、Double、Long等类型,于是,Mybatis把这些方法封装到一个类中,取名叫XPathParser

XPathParser 的构造方法有 16 个之多,当然基本都非常相似

XPathParser 提供了一系列的 #eval* 方法,用于获得 Boolean、Short、Integer、Long、Float、Double、String、Node 类型的元素或节点的“值”。当然,虽然方法很多,但是都是基于 #evaluate(String expression, Object root, QName returnType) 方法

private Node node;
private String body;
private Properties attributes;
private XPathParser xpathParser;

Mybatis又把上面几个必要属性封装到一个类中,取名叫XNode。

这就是这俩兄弟的来历。概念多了易乱,可以忽视XNodeXPathParser的存在,心中只有NodeXPath

标签:解析器,Node,String,初始化,Mybatis,XPathConstants,MyBatis,new,Reflector
来源: https://www.cnblogs.com/hochan100/p/15125321.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有