二、MyBatis源码解析器
MyBatis源码解析器
1. XPathParser
基于 Java XPath 解析器,用于解析 MyBatis
mybatis-config.xml
和**Mapper.xml
等 XML 配置文件。所在包: org.apache.ibatis.parsing
1.1 成员属性
1 |
|
document:
- XML 被解析后,生成的
org.w3c.dom.Document
对象
- XML 被解析后,生成的
validation:
- 是否校验 XML, 一般为
true
- 是否校验 XML, 一般为
entityResolver:
- XML 实体解析器, 默认情况下, 对 XML 进行校验时, 会基于 XML 文档开始位置指定的 DTD 文件或 XSD 文件, 由于需要网络加载, MyBatis 自定义了 EntityResolver 的实现,达到使用本地 DTD 文件
xpath:
- 用于查询XML中的节点和元素(https://www.yiibai.com/java_xml/java_xpath_parse_document.html)
variables: Properties对象, 用来替换需要动态配置的属性值
1
2
3
4
5
6
7
8
9
10
11
12<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
<--可以用properties文件,也可以使用properties标签,如下用username替换占位符-->
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
1.2 构造方法
以其中一个构造方法为例:
1 |
|
调用 #commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver)
调用共用的构造方法
1
2
3
4
5
6
7
8private void commonConstructor(boolean validation, Properties variables, EntityResolver entityResolver) {
this.validation = validation;
this.entityResolver = entityResolver;
this.variables = variables;
// 创建 XPathFactory 对象
XPathFactory factory = XPathFactory.newInstance();
this.xpath = factory.newXPath();
}
调用 #createDocument(InputSource inputSource)
将xml文件解析成Document对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45/**
* 创建 Document 对象
*
* @param inputSource XML 的 InputSource 对象
* @return Document 对象
*/
private Document createDocument(InputSource inputSource) {
// important: this must only be called AFTER common constructor
try {
// 1. 创建 DocumentBuilderFactory 对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setValidating(validation); // 设置是否验证xml
factory.setNamespaceAware(false);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(false);
factory.setCoalescing(false);
factory.setExpandEntityReferences(false);
// 2. 创建 DocumentBuilder 对象
DocumentBuilder builder = factory.newDocumentBuilder();
builder.setEntityResolver(entityResolver); // 设置实体解析器
builder.setErrorHandler(new ErrorHandler() {
@Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void warning(SAXParseException exception) throws SAXException {
// NOP
}
});
// 3. 解析 xml 文件
return builder.parse(inputSource);
} catch (Exception e) {
throw new BuilderException("Error creating document instance. Cause: " + e, e);
}
}
1.3 eval方法族
XPathParser 提供了一系列的 #eval* 方法,用于获得 Boolean、Short、Integer、Long、Float、Double、String、Node 类型的元素或节点的“值”, 都是基于 #evaluate(String expression, Object root, QName returnType)
1 |
|
- 调用 xpath 的 evaluate(String expression, Object item, QName returnType) 方法, 获得指定元素或节点的值
1.3.1 eval 元素
eval 元素的方法,用于获得 Boolean、Short、Integer、Long、Float、Double、String 类型的元素的值, 以String为例
1 |
|
1.3.2 eval节点
eval 元素的方法,用于获得 Node 类型的节点的值
1 |
|
1.4 XMLMapperEntityResolver
实现 EntityResolver 接口,MyBatis 自定义 EntityResolver 实现类,用于加载本地的
mybatis-3-config.dtd
和mybatis-3-mapper.dtd
这两个 DTD 文件, 所在包 org.apache.ibatis.builder.xml
1 |
|
1.5 GenericTokenParser
通用的 Token 解析器, 解析openToken开头closeToken结尾的Token, 所在包 org.apache.ibatis.parsing
1 |
|
1.6 PropertyParser
动态属性解析器, 所在包 org.apache.ibatis.parsing
1 |
|
1.7 TokenHandler
Token处理器接口
1 |
|
1.7.1 VariableTokenHandler
PropertyParser 的内部静态类,变量 Token 处理器
构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/**
* 变量 Properties 对象
*/
private final Properties variables;
/**
* 是否开启默认值功能。默认为 {@link #ENABLE_DEFAULT_VALUE}
*/
private final boolean enableDefaultValue;
/**
* 默认值的分隔符。默认为 {@link #KEY_DEFAULT_VALUE_SEPARATOR} ,即 ":" 。
*/
private final String defaultValueSeparator;
private VariableTokenHandler(Properties variables) {
this.variables = variables;
this.enableDefaultValue = Boolean.parseBoolean(getPropertyValue(KEY_ENABLE_DEFAULT_VALUE, ENABLE_DEFAULT_VALUE));
this.defaultValueSeparator = getPropertyValue(KEY_DEFAULT_VALUE_SEPARATOR, DEFAULT_VALUE_SEPARATOR);
}
private String getPropertyValue(String key, String defaultValue) {
return variables == null ? defaultValue : variables.getProperty(key, defaultValue);
}
1.7.2 HandleToken
1 |
|