(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨
👀👀👀 个人博客:小奥的博客
👍👍👍:个人优快云
⭐️⭐️⭐️:传送门
🍹 本人24应届生一枚,技术和水平有限,如果文章中有不正确的内容,欢迎多多指正!
📜 欢迎点赞收藏关注哟! ❤️
解析器模块
解析器模块主要提供了两个功能:
- 为解析MyBatis配置文件、Mapper映射文件等提供支持
- 为处理动态SQL语句中的占位符提供支持
MyBatis的解析器模块目录如下:
主要包路径:org.apache.ibatis.parsing
解析器模块的包结构如上图所示,其中,XPathParser 和XNode 主要用来解析 XML,PropertyParser、GenericTokenParser 、TokenHandler 主要用于标记处理(占位符),ParsingException是异常处理类。
GenericTokenParser
:通用的Token解析器(即占位符解析器),解析xml文件中的占位符${}
,并返回对应的值ParsingException
:异常处理类PropertyParser
:动态属性解析器TokenHandler
:标记处理接口XNode
:XML节点,封装了NodeXPathParser
:基于Java XPath 解析器,用于解析MyBatis的mybatis-config.xml
和Mapper.xml
等XML配置文件
① TokenHandler
TokenHandler是一个接口,定义了一个handleToken方法,该方法主要用于标记处理,具体实现在各自实现类中完成。主要是配合通用标记解析器GenericTokenParser类完成对配置文件等的解析工作,其中TokenHandler主要完成处理,而解析器主要实现前序工作——解析。
public interface TokenHandler {
/**
* 标记处理接口
* @param content
* @return
*/
String handleToken(String content);
}
② XNode
XNode作为解析xml配置文件的基础类,其中封装了Node节点,并且提供了常见的解析一个Node节点需要的功能和方法。
public class XNode {
private final Node node; // mark 被包装的org.w3c.dom.Node对象
private final String name; // mark 节点名称
private final String body; // mark 节点内容
private final Properties attributes; // mark 节点属性集合
private final Properties variables; // mark 配置文件中<properties>节点下定义的键值对
private final XPathParser xpathParser; // mark 封装了XPath解析器,负责XNode对象的生成,并提供解析XPath表达式的功能
public XNode(XPathParser xpathParser, Node node, Properties variables) {
this.xpathParser = xpathParser;
this.node = node;
this.name = node.getNodeName();
this.variables = variables;
this.attributes = parseAttributes(node);
this.body = parseBody(node);
}
public XNode newXNode(Node node) {
return new XNode(xpathParser, node, variables); // mark 根据传入的Node对象,创建XNode对象实例
}
/**
* 获取父节点
* @return 父节点是Element类型,返回封装好的XNode节点,否则返回null
*/
public XNode getParent() {
Node parent = node.getParentNode();
if (!(parent instanceof Element)) {
return null;
}
return new XNode(xpathParser, parent, variables);
}
/**
* 获取节点路径
* @return 节点的路径值
* 比如 <A><B><C><C/><B/><A/>,对于C节点来说节点路径就是 A/B/C
*/
public String getPath() {
StringBuilder builder = new StringBuilder();
Node current = node; // mark 当前节点
while (current instanceof Element) {
if (current != node) {
builder.insert(0, "/");
}
builder.insert(0, current.getNodeName());
current = current.getParentNode(); // mark 向上追溯节点,直到顶层节点
}
return builder.toString();
}
/**
* 获取节点的识别码
* @return 返回唯一标识字符串,如下面的C节点的唯一标识字符串就是 A_B[bid]_C[cid]
* @Code <A>
* <B id="bid">
* <C id="cid" value="cvalue"/>
* </B>
* </A>
*/
public String getValueBasedIdentifier() {
StringBuilder builder = new StringBuilder();
XNode current = this;
while (current != null) {
if (current != this) {
builder.insert(0, "_");
}
String value = current.getStringAttribute("id",
current.getStringAttribute("value", current.getStringAttribute("property", (String) null)));
if (value != null) {
value = value.replace('.', '_');
builder.insert(0, "]");
builder.insert(0, value);
builder.insert(0, "[");
}
builder.insert(0, current.getName());
current = current.getParent();
}
return builder.toString();
}
/**
* evalXXX()方法,调用XPathParser方法在当前节点下寻找符合表达式条件的节点,通常是文本节点,并
* 将值转为为指定的类型,如果值无法转化为指定类型,则会报错。
* 【支持数据类型】 String、Boolean、Double、Node、List<Node>
*/
...
/**
* getXXXBody()方法:获取文本内容并将其转化为指定的数据类型
* 【支持的数据类型】String、Boolean、Integer、Long、Double、Float
*/
...
/**
* getXxxAttribute()方法:获取节点指定属性的属性值并将其转化为指定的数据类型
*/
...
/**
* 获取子节点,对Node.getChildNodes()做相应的封装得到List<XNode>
* @return 子节点集合
*/
public List<XNode> getChildren() {
List<XNode> children =