XMLConfigBuilder
根据上一节内容我们已经知道了,XML配置文件的解析全部是通过XMLConfigBuilder进行完成的,该类的类继承结构如下:
其中BaseBuilder提供了一个配置解析器所需要的大部分工具方法,以及通用的变量、操作这些通用变量的方法。通用的变量分别如下:
- Configuration:configuration,用于存储解析过程中用于担当解析结果的Configuration对象
- TypeAliasRegistry: typeAliasRegistry,用于存储类型别名的注册表
- TypeHandlerRegistry: typeHandlerRegistry,用于存储类型处理器的注册表
对于一个配置解析器来说,保存结果的对象肯定是必须的,剩下两个注册表分别是别名和类型处理器,这到底是谁通用的呢。我们考察BaseBuilder
的子类,类图如下:
可以看到,BaseBuilder
有7个子类,分别是:
- XMLConfigBuilder:Mybatis xml配置解析器
- XMLScriptBuilder:Mybatis 动态SQL标签解析器
- XMLMapperBuilder:Mybatis mapper标签配置解析器
- SqlSourceBuilder:Mybatis ParameterMap标签解析器
- XMLStatementBuiler: Mybatis SQL语句解析器,解析insert、update、select标签
- MapperBuilderAssistant:Mapper解析时的辅助缓存
- ParameterMappingTokenHandler:parameterMapping的解析工具
由于别名注册表和类型处理器是除了配置文件外每个Mapper文件都要用的,因此,就把它放在了BaseBuilder中。除了XMLConfigBuilder以外所有的其他Builder都是为<mapper>
服务的。
所以我们可以根据配置文件来对代码进行分析,首先分析Mybatis的基本配置解析,然后再分析<mapper>
标签的配置解析。
首先让我们分析XMLConfigBuilder的解析Mybatis配置的逻辑:也就是XMLConfigBuilder
的parse()
方法:
public Configuration parse() {
// 处理重复解析问题
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
// 解析configuration标签
parseConfiguration(parser.evalNode("/configuration"));
// 返回解析结果
return configuration;
}
根据Mybatis文档可知,Mybatis配置文档层级结构如下:
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
所以要从根节点configuration
开始解析,具体解析逻辑在parseConfiguration(XNode root)
方法中,该方法代码如下:
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
// 解析properties标签
propertiesElement(root.evalNode("properties"));
// 解析settings标签
// 该方法就是将<settings>标签中声明的key-value值转化为Properties格式,然后统一进行设置
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 加载虚拟文件系统,毕竟是要从文件系统读取配置
// 此处可以忽略
loadCustomVfs(settings);
// 解析typeAliases标签
// 将别名存入到TypeAliasRegistry中
typeAliasesElement(root.evalNode("typeAliases"));
// 解析plugins标签
pluginElement(root.evalNode("plugins"));
// 解析objectFactory标签
// 对于Mybatis来说,返回结果对象都由ObjectFactory生成,这里就对其进行配置
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// 解析environments标签
environmentsElement(root.evalNode("environments"));
// 解析databaseIdProvier标签
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 解析typeHandlers 标签
typeHandlerElement(root.evalNode("typeHandlers"));
// 解析mappers标签
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
事实上根据方法名我们就可以知道哪个方法用于解析哪个标签。由于笔者时间有限,接下来会对几个常用标签的解析方法进行详细说明,其中包括:
- 插件标签
- mapper标签
更多的标签将在后续进行补充。接下来让我们先去查看<plugin>
标签的解析过程吧!