概述
解析器模块主要提供了两个功能:
- 对 XPath 进行封装,为 MyBatis 初始化时解析 mybatis-config.xml 配置文件以及映射文件提供支持「使用过 MyBatis 都知道,需要配置文件以及 Mapper.xml 映射文件,而加载解析这些配置就是这个模块提供的支持」
- 为处理动态 SQL 语句中的占位符提供支持「我们使用 #{} 占位符时的处理」
XPathParser
是 MyBatis 基于 Java XPath 封装的解析器,用于 mybatis-config.xml 以及 Mapper.xml 文件的解析。
属性解析
private final Document document;
private boolean validation; //
private EntityResolver entityResolver; //
private Properties variables; //
private XPath xpath; //
复制代码
- document : org.w3c.dom.Document; Java 自带的 Document 对象
- validation: 是否开启验证,是否校验 XML,一般是 true
- entityResolver: 用于加载本地 DTD 文件,防止从网络上获取 DTD 文件加载,避免网络不稳定的情况
- variables: mybatis-config 中 标签定义的键值对集合
- xpath: XPath 对象,也是Java 自带的,用于查询 XML 中的节点和元素。
构造函数
它里面有很多构造函数,随便选一个看看:
public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
commonConstructor(validation, variables, entityResolver);
this.document = createDocument(new InputSource(inputStream));
}
复制代码
- commonConstructor() 方法就是对 XPathParser 属性的初始化
- createDocument 从配置文件中获取 Document 对象
其中 entityResolver ,如果我们去 XMLConfigBuilder 类文件中,就会发现:里面的是 XMLMapperEntityResolver(),里面的核心方法是 resolveEntity :就是加载本地的 dtd 文件。
public XMLConfigBuilder(Reader reader, String environment, Properties props) {
this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}
复制代码
eval* 方法
里面提供了很多 eval* 的方法,用于获得 Boolean、Short、Integer、Long、Float、Double、String、Node 类型的元素或节点的值。但是他们都是基于 evaluate(String expression,Object root,QName returnType)方法。
//获取指定元素或节点的值
private Object evaluate(String expression, Object root, QName returnType) {
try {
return xpath.evaluate(expression, root, returnType);
} catch (Exception e) {
throw new BuilderException("Error evaluating XPath. Cause: " + e, e);
}
}
复制代码
GenericTokenParser
上面的 XPathParser#evalString() 也是会生成此对象进行解析的。
这是一个通用的 Token 解析器,里面就一个 parse 解析方法:它会顺序查找 opentoken、closetoken ,解析得到占位符的字面值,并将其交给 TokenHandler 处理,然后将解析结果重新拼装成字符串返回。
代码我就不贴了,可以直接去源码中搜索看看。
PropertyParser
动态属性解析器。
里面构造函数是静态的,提供了静态的 parse 解析方法。
public static String parse(String string, Properties variables) {
VariableTokenHandler handler = new VariableTokenHandler(variables);
GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
return parser.parse(string);
}
复制代码
其中制定了 TokenHandler 实现类:VariableTokenHandler ;然后 解析是占位符是 ${}。
TokenHandler
token 处理器接口,里面有四个实现方法。有点策略模式的意思。上面的 PropertyParser 里面有一个静态内部类:就是此接口的实现:VariableTokenHandler。
总结
- 解析 XML 的类:XPathParser 是基于 Java rt.jar 包里面的内容 org.w3c.dom、org.xml.sax、javax.xml 一般都是直接使用,一般平时使用的更多的是 dom4j 这个 jar 包。
- GenericTokenParser#parse 方法,主要就是替换占位符,自己开发中也写过这种解析方法,但是就一个方法完事,不像这里的方法边界考虑的很好,而且使用了策略模式将不同的处理分到具体的实现类。框架的设计就是吊。
参考
- 徐郡明 《MyBatis 技术内幕》「2.1 解析器模块」