文档章节

Mybatis3.3.x技术内幕(七):Mybatis初始化之六个工具

祖大俊
 祖大俊
发布于 2016/05/01 16:35
字数 1494
阅读 2217
收藏 20

全民欢庆的五一劳动节,可谓是赏花赏月赏秋香的好季节,炎炎夏日,柳絮飞扬,短裙飞舞,低胸抢镜,是旅游撩妹裸奔等精彩活动的不二选择,不过,这显然与我无关。


终于要开启Mybatis的初始化过程分析了,是不是等的花儿都要开放了呢?

一般的框架分析思路都是从启动、初始化说起,然而,由于没有心理准备,初始化过程中会瞬间涌入大量的概念、类等等,类之间又存在爆炸性延伸,反而吓退了读者,有种吃不下这块肥肉的感觉。所以,我选择优先介绍一些易于理解的框架概念,然后再阅读和分析框架的启动和初始化流程,有了事先的精心准备,肥肉也就不再肥了。

我一直在反思,我的博文是否写的过长了,读者是否读的很累,是否没有描述清楚内容,是否没有抓住重点。因此,我大胆创新了博文的写作模式,叫精炼博文



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

(Made In Edrawmax)

图中展示了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的属性值。

(Made In Intellij Idea IDE)

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的“正则表达式”。

我们使用XPath技术,来编写一个小例子。

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<Node>集合,那么需要简单封装一下。

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<Node>,可能还有Integer、Double、Long等类型,于是,Mybatis把这些方法封装到一个类中,取名叫XPathParser


在面对一个Node时,假设我想要把Node的属性集合都以键、值对的形式,放到Properties对象里,同时把Node的body体也通过XPathParser解析出来,并保存起来(一般是Sql语句),方便程序使用,代码可能会是这样的。

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

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


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


精炼博文模式,读读更健康,她好我也好。


版权提示:文章出自开源中国社区,若对文章感兴趣,可关注我的开源中国社区博客(http://my.oschina.net/zudajun)。(经过网络爬虫或转载的文章,经常丢失流程图、时序图,格式错乱等,还是看原版的比较好)

© 著作权归作者所有

共有 人打赏支持
祖大俊
粉丝 748
博文 32
码字总数 52477
作品 0
昌平
私信 提问
加载中

评论(5)

godwarkill
godwarkill
很不错
郑龙飞
郑龙飞
写的很好。。。。
jp_ing
jp_ing
写的非常之好....竟然连我这种新手都能读懂.....
谁说不能超过10个字
谁说不能超过10个字
写的很好……
bjava
bjava
写的非常好, 谢谢。
Mybatis3.3.x技术内幕(一):SqlSession和SqlSessionFactory列传

前言:我长大了,成年了,有需求,但我单身,所以我要讨个媳妇,要求是:漂亮、高挑、身材好、笑容甜美…… 和A相亲:漂亮,不够高挑。 和B相亲:高挑,身材不够好。 和C相亲:身材好,笑容不...

祖大俊
2016/04/25
3.3K
2
Mybatis3.3.x技术内幕(八):Mybatis初始化流程(上)

Mybatis初始化流程,其实就是组装重量级All-In-One对象Configuration的过程,主要分为系统环境参数初始化和Mapper映射初始化,其中Mapper映射初始化尤为重要。 inputStream = Resources.getR...

祖大俊
2016/05/02
1K
2
Mybatis3.3.x技术内幕(十二):Mybatis之TypeHandler

Mybatis中的TypeHandler有两个功能,一个是完成javaType至jdbcType的转换,另外一个是完成jdbcType至javaType的转换。 public interface TypeHandler<T> { void setParameter(PreparedStatem......

祖大俊
2016/05/06
991
0
Mybatis3.3.x技术内幕(九):Mybatis初始化流程(中)

Mybatis初始化流程,其实就是组装重量级All-In-One对象Configuration的过程,主要分为系统环境参数初始化和Mapper映射初始化。 上一节中,粗略讲述了Mybatis初始化的基本步骤,本节,将详细分...

祖大俊
2016/05/02
901
0
Mybatis3.3.x技术内幕(十):Mybatis初始化流程(下)

Mybatis初始化过程中,解析parameterMap、resultMap、"select|insert|update|delete"元素,无疑是重头戏。本节将详细分析解析过程。 元素parameterMap将会解析为ParameterMap对象,该对象包含...

祖大俊
2016/05/04
851
0

没有更多内容

加载失败,请刷新页面

加载更多

如果让你写一个消息队列,该如何进行架构设计?

面试题 如果让你写一个消息队列,该如何进行架构设计?说一下你的思路。 面试官心理分析 其实聊到这个问题,一般面试官要考察两块: 你有没有对某一个消息队列做过较为深入的原理的了解,或者...

李红欧巴
今天
4
0
错题

无知的小狼
今天
2
0
PowerShell因为在此系统中禁止执行脚本的解决方法

参考:window系统包管理工具--chocolatey 报错提示: & : 无法加载文件 C:\Users\liuzidong\AppData\Local\Temp\chocolatey\chocInstall\tools\chocolateyInstall.ps1,因为在此系统上禁止运...

近在咫尺远在天涯
今天
3
0
TP5 跨域请求处理

https://blog.csdn.net/a593706205/article/details/81774987 https://blog.csdn.net/wyk9916/article/details/82315700...

15834278076
今天
3
0
深入理解java虚拟机-Java内存区域与内存溢出异常

深入理解java虚拟机 Java内存区域与内存溢出异常 运行时数据区域 程序计数器 线程私有,内存小,是当前线程执行的字节码行号指示器,字节码解释器通过改变这个计数器的值来选取下一条需要执行...

须臾之余
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部