概述
接下來我們進入mybatis的初始化配置階段。
配置階段就是讀取mybatis的配置文件及我們編寫的XML文件。
在講解mybatis的初始化配置之前,我們先了解初始化配置階段要用到的基礎支撐組件。
這一篇講解的是xml文件解析器組件
DOM
java編程中我們常見的XML解析方式有三種:
- DOM解析方式:加載整個XML到內存構建DOM樹,數據量較大時,較消耗內存
- SAX解析方式:基於事件模型的XML解析方式,流式處理方式,處理XML文檔只能向後單項進行,沒法自由導航,且需要開發人員自己維護節點關係,面對複雜的XML程序會比較複雜。
StAX解析方式:同時支持DOM和SAX解析方式。
上面僅對java中常見的XML解析幾種方式做簡要介紹,大致瞭解即可。
mybatis採用的是DOM解析方式,並結合了XPath工具。
XPath之於XML類似於Sql之於數據庫。就是XML的一個查詢工具。
通過一段簡單代碼瞭解DOM和XPath
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yanlink.mapper.SysUserMapper">
<resultMap id="sysUserMap" type="com.yanlink.entity.SysUser">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="password" column="password"/>
</resultMap>
<select id="getUser" resultType="SysUser">
select id,name,password,sex from sys_user where id=#{id}
</select>
</mapper>
上面是一個我們經常編寫的操作數據庫的xml文件
下面我通過xpath來讀取這個xml文件
public class XPathDemo {
public static void main(String[] args) {
try {
InputStream inputStream = XPathDemo.class.getResourceAsStream("/mapper/SysUserMapper.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(inputStream);
XPath xPath = XPathFactory.newInstance().newXPath();
Node mapper = (Node) xPath.evaluate("/mapper", document, XPathConstants.NODE);
System.out.println(mapper.getNodeName()+" "+mapper.getAttributes().getNamedItem("namespace"));
// 輸出mapper namespace="com.yanlink.mapper.SysUserMapper"
Node resultMap = (Node) xPath.evaluate("resultMap", mapper, XPathConstants.NODE);
System.out.println(resultMap.getNodeName()+" "+resultMap.getAttributes().getNamedItem("id")+" "+resultMap.getAttributes().getNamedItem("type"));
// 輸出:resultMap id="sysUserMap" type="com.yanlink.entity.SysUser"
NodeList results = (NodeList) xPath.evaluate("result", resultMap, XPathConstants.NODESET);
for (int i = 0; i < results.getLength(); i++) {
Node result = results.item(i);
NamedNodeMap nodeMap = result.getAttributes();
System.out.println(result.getNodeName()+" "+nodeMap.getNamedItem("property")+" "+nodeMap.getNamedItem("column"));
}
// 輸出: result property="name" column="name"
//result property="sex" column="sex"
//result property="password" column="password"
/**
* 我們還可以直接定位到對應的node
*/
Node select = (Node) xPath.evaluate("//select[@id='getUser']", document, XPathConstants.NODE);
NamedNodeMap selectNameNodeMap = select.getAttributes();
System.out.println(select.getNodeName()+" "+ selectNameNodeMap.getNamedItem("id") +" "+selectNameNodeMap.getNamedItem("resultType"));
// 輸出:select id="getUser" resultType="SysUser"
} catch (Exception e) {
e.printStackTrace();
}
}
}
相信通過上面一段代碼,我們大致可能瞭解XPath是做什麼的了。
這裏並不是要大家來深入瞭解XPath,如果對這個確實感興趣,可以去查閱相關的資料,我們這裏的目的還是介紹下XPath的概念,便於我們引入myabtis的xml解析工具XPathParser
XPathParser
XPathParser其實就是對XPath操作XML文檔的封裝。
看下XPathParser的屬性
private final Document document;
private XPath xpath;
其實也就兩個東西,一個document,一個xpath,document是文檔,xpath讀取文檔信息
再看看其使用率比較高的方法
public List<XNode> evalNodes(Object root, String expression) {
List<XNode> xnodes = new ArrayList<XNode>();
NodeList nodes = (NodeList) evaluate(expression, root, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
xnodes.add(new XNode(this, nodes.item(i), variables));
}
return xnodes;
}
public XNode evalNode(Object root, String expression) {
Node node = (Node) evaluate(expression, root, XPathConstants.NODE);
if (node == null) {
return null;
}
return new XNode(this, node, variables);
}
private Object evaluate(String expression, Object root, QName returnType) {
try {
return xpath.evaluate(expression, root, returnType);
} catch (Exception e) {
throw new RuntimeException("Error evaluating XPath. Cause: " + e, e);
}
}
注意這裏返回的不再是Node對象,而是MyBatis封裝的XNode對象了
public class XNode {
private final Node node;
private final String name;
private final String body;
private final Properties attributes;
private final Properties variables;
private final XPathParser xpathParser;
private Properties parseAttributes(Node n) {
Properties attributes = new Properties();
NamedNodeMap attributeNodes = n.getAttributes();
if (attributeNodes != null) {
for (int i = 0; i < attributeNodes.getLength(); i++) {
Node attribute = attributeNodes.item(i);
String value = PropertyParser.parse(attribute.getNodeValue(), variables);
attributes.put(attribute.getNodeName(), value);
}
}
return attributes;
}
}
XNode也就是對Node進行了一次封裝,讓我們更好地操作Node的屬性,及獲取其內容
如果對我實現的簡化的XPathParser感興趣可以下載下面的項目