Mybatis3.3.x技術內幕(七):Mybatis初始化之六個工具

全民歡慶的五一勞動節,可謂是賞花賞月賞秋香的好季節,炎炎夏日,柳絮飛揚,短裙飛舞,低胸搶鏡,是旅遊撩妹裸奔等精彩活動的不二選擇,不過,這顯然與我無關。java


終於要開啓Mybatis的初始化過程分析了,是否是等的花兒都要開放了呢?node

通常的框架分析思路都是從啓動、初始化提及,然而,因爲沒有心理準備,初始化過程當中會瞬間涌入大量的概念、類等等,類之間又存在爆炸性延伸,反而嚇退了讀者,有種吃不下這塊肥肉的感受。因此,我選擇優先介紹一些易於理解的框架概念,而後再閱讀和分析框架的啓動和初始化流程,有了事先的精心準備,肥肉也就再也不肥了。正則表達式

我一直在反思,個人博文是否寫的過長了,讀者是否讀的很累,是否沒有描述清楚內容,是否沒有抓住重點。所以,我大膽創新了博文的寫做模式,叫精煉博文express



Mybatis的初始化過程,就是組裝Configuration的過程,在這個過程當中,用到了一些工具,我列舉了六個基本工具,如圖所示。
緩存

(Made In Edrawmax)網絡

圖中展現了XMLConfigBuilder爲了組裝出Configuration對象所做出的努力,配備了至少六個基本工具。本文的重點,就是分析這六個工具的做用。mybatis


好怕怕啊,一會兒分析六個那麼多。別怕,每一個工具不超過三行代碼,你就會完全明白(相信你本身)。app

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)。(通過網絡爬蟲或轉載的文章,常常丟失流程圖、時序圖,格式錯亂等,仍是看原版的比較好)

相關文章
相關標籤/搜索