` 处。
- 所以所以所以,胖友可以耐心看下这段逻辑,也可以忽略,大体理解就好。
- 关于 `handler` 这个 TokenHandler ,详细见 [「5. TokenHandler」](https://svip.iocoder.cn/MyBatis/parsing-package/#) 。当然,这也是为什么 GenericTokenParser 叫做**通用**的原因,而 TokenHandler 处理**特定**的逻辑。
# 5. PropertyParser
`org.apache.ibatis.parsing.PropertyParser` ,动态属性解析器。代码如下:
```
// PropertyParser.java
public class PropertyParser {
// ... 省略部分无关的
private PropertyParser() { // <1>
// Prevent Instantiation
}
public static String parse(String string, Properties variables) { // <2>
// <2.1> 创建 VariableTokenHandler 对象
VariableTokenHandler handler = new VariableTokenHandler(variables);
// <2.2> 创建 GenericTokenParser 对象
GenericTokenParser parser = new GenericTokenParser("${", "}", handler);
// <2.3> 执行解析
return parser.parse(string);
}
}
```
- `<1>` ,构造方法,修饰符为 `private` ,禁止构造 PropertyParser 对象,因为它是一个静态方法的工具类。
- ```
<2>
```
,基于
```
variables
```
变量,替换
```
string
```
字符串中的动态属性,并返回结果。
- `<2.1>` ,创建 VariableTokenHandler 对象。
- ```
<2.2>
```
,创建 GenericTokenParser 对象。
- 我们可以看到,`openToken = {` ,`closeToken = }` ,这不就是上面看到的 `${username}` 和 `{password}` 的么。
- 同时,我们也可以看到,`handler` 类型为 VariableTokenHandler ,也就是说,通过它实现**自定义**的处理逻辑。关于它,在 [「6.1 VariableTokenHandler」](https://svip.iocoder.cn/MyBatis/parsing-package/#) 中详细解析。
- `<2.3>` ,调用 `GenericTokenParser#parse(String text)` 方法,执行解析。
# 6. TokenHandler
`org.apache.ibatis.parsing.TokenHandler` ,Token 处理器接口。代码如下:
```
// TokenHandler.java
public interface TokenHandler {
/**
* 处理 Token
*
* @param content Token 字符串
* @return 处理后的结果
*/
String handleToken(String content);
}
```
- `#handleToken(String content)` 方法,处理 Token ,在 [「4. GenericTokenParser」](https://svip.iocoder.cn/MyBatis/parsing-package/#) 中,我们已经看到它的调用了。
TokenHandler 有四个子类实现,如下图所示:[](http://static.iocoder.cn/images/MyBatis/2020_01_07/02.png)TokenHandler 子类
- 本文暂时只解析 VariableTokenHandler 类,因为只有它在 `parsing` 包中,和解析器模块相关。
## 6.1 VariableTokenHandler
VariableTokenHandler ,是 PropertyParser 的内部静态类,变量 Token 处理器。具体什么用途?上面不是已经整的明明白白啦,就不重复解释啦。
### 6.1.1 构造方法
```
// PropertyParser.java
private static final String KEY_PREFIX = "org.apache.ibatis.parsing.PropertyParser.";
/**
* The special property key that indicate whether enable a default value on placeholder.
*
* The default value is {@code false} (indicate disable a default value on placeholder)
* If you specify the {@code true}, you can specify key and default value on placeholder (e.g. {@code ${db.username:postgres}}).
*
* @since 3.4.2
*/
public static final String KEY_ENABLE_DEFAULT_VALUE = KEY_PREFIX + "enable-default-value";
/**
* The special property key that specify a separator for key and default value on placeholder.
*
* The default separator is {@code ":"}.
*
* @since 3.4.2
*/
public static final String KEY_DEFAULT_VALUE_SEPARATOR = KEY_PREFIX + "default-value-separator";
private static final String ENABLE_DEFAULT_VALUE = "false";
private static final String DEFAULT_VALUE_SEPARATOR = ":";
// VariableTokenHandler 类里
/**
* 变量 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);
}
```
- 虽然看起来有一大坨的变量,但是不要怕。
- `variables` 属性,变量 Properties 对象。
- `enableDefaultValue` 属性,是否开启默认值功能。默认为 `ENABLE_DEFAULT_VALUE` ,即**不开启**。想要开启,可以配置如下:
```
```
- `defaultValueSeparator` 属性,默认值的分隔符。默认为 `KEY_DEFAULT_VALUE_SEPARATOR` ,即 `":"` 。想要修改,可以配置如下:
```
```
- 分隔符被修改成了 `?:` 。
### 6.1.2 handleToken
```
// VariableTokenHandler 类里
@Override
public String handleToken(String content) {
if (variables != null) {
String key = content;
// 开启默认值功能
if (enableDefaultValue) {
// 查找默认值
final int separatorIndex = content.indexOf(defaultValueSeparator);
String defaultValue = null;
if (separatorIndex >= 0) {
key = content.substring(0, separatorIndex);
defaultValue = content.substring(separatorIndex + defaultValueSeparator.length());
}
// 有默认值,优先替换,不存在则返回默认值
if (defaultValue != null) {
return variables.getProperty(key, defaultValue);
}
}
// 未开启默认值功能,直接替换
if (variables.containsKey(key)) {
return variables.getProperty(key);
}
}
// 无 variables ,直接返回
return "${" + content + "}";
}
```
- 比较简单,胖友自己看。
# 666. 彩蛋
小文一篇。按照前面的代码统计,我们已经看掉了小 1000 行的代码了。继续搞起。
参考和推荐如下文章:
- 徐郡明 [《MyBatis 技术内幕》](https://item.jd.com/12125531.html) 的 [「2.1 解析器模块」](https://svip.iocoder.cn/MyBatis/parsing-package/#) 小节
- 祖大俊 [《Mybatis3.3.x技术内幕(七):Mybatis初始化之六个工具》](https://my.oschina.net/zudajun/blog/668596)