接下来我们进入mybatis的初始化配置阶段。
配置阶段就是读取mybatis的配置文件及我们编写的XML文件。
在讲解mybatis的初始化配置之前,我们先了解初始化配置阶段要用到的基础支撑组件。
这一篇讲解的是xml文件解析器组件
java编程中我们常见的XML解析方式有三种:
- DOM解析方式:加载整个XML到内存构建DOM树,数据量较大时,较消耗内存
- SAX解析方式:基于事件模型的XML解析方式,流式处理方式,处理XML文档只能向后单项进行,没法自由导航,且需要开发人员自己维护节点关系,面对复杂的XML程序会比较复杂。
StAX解析方式:同时支持DOM和SAX解析方式。
上面仅对java中常见的XML解析几种方式做简要介绍,大致了解即可。
mybatis采用的是DOM解析方式,并结合了XPath工具。
XPath之于XML类似于Sql之于数据库。就是XML的一个查询工具。
通过一段简单代码了解DOM和XPath
上面是一个我们经常编写的操作数据库的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其实就是对XPath操作XML文档的封装。
看下XPathParser的属性
private final Document document;
private XPath xpath;
其实也就两个东西,一个document,一个xpath,document是文档,xpath读取文档信息
再看看其使用率比较高的方法
public List evalNodes(Object root, String expression) {
List xnodes = new ArrayList();
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感兴趣可以下载下面的项目