
该系列文章针对 Mybatis 3.5.1 版本
Mybatis 中 <mappers>
标签解析,主要是为了得到两大部分数据
1、Mapper.class 接口
2、SQL 执行语句,结果集映射关系等数据
在上一章中提到了 Mapper.class 文件的解析,Mapper.class 是接口文件,该接口是发起SQl执行调用的 API 入口,所有相关的操作都在其代理类 MapperProxy
中完成。
在上一章中忽略了 Mapper.class
文件中 @Select
等 SQL 语句注解的解析,本次章节将和 xml 中的 sql 解析一起分析。
`<mapper>` 标签解析入口
来回顾一下,XMLConfigBuilder
解析时序简图,如下:

在时序图中 <mappers>
加载解析在 XMLConfigBuilder#mapperElement
中完成,相关解析代码如下:

如上述代码,针对 <mappers>
子标签的解析分为两种:扫包批量解析和单个文件解析。
而无论是扫包批量解析亦或者单个文件解析,都会对 xml 文件 和 class 文件进行解析处理。
上一章以单个文件解析为入口分析 Mapper.class
文件的加载。
并提到了单个文件 <mapper>
标签配置的三种属性:
resource
url
class
这三种属性的配置都会尝试解析 xml 中的数据和 Mapper.class 上的 @Select
等注解,而 resource 和 url 所配置的直接就是 xml 路径,加载了 xml 通过命名空间即可找到关联对应的 Mapper.class 进行解析。
而 class 配置,如果要找到对应的 xml 文件,需要按照既定的规约给 xml 文件命名,规约为:Mapper.class.getName()
+ .xml
本次 sql 相关解析以单个文件的 resource 配置解析为入口展开,对应的解析入口代码为

从代码中,能够知道完成 xml 文件解析的类为 XMLMapperBuilder
,而进行解析的入口方法为 XMLMapperBuilder#parse
。
来具体看看 XMLMapperBuilder#parse
XML 文件解析入口代码

如上述代码,解析入口职责也很清晰,对 xml 文件和 mapper class 文件进行了解析。
下面分别进入到各自的方法中查看各自是如何进行 sql 解析的。
xml 文件解析
xml 文件解析代码入口方法
XMLMapperBuilder#configurationElement
相关代码如下:

在上述解析代码中,针对 xml 文件中的各种标签进行解析,如 <cache-ref>
、<cache>
、<resultMap>
、<insert>
等。
解析后的结果会被存储到 Configuration
中,例如:
<cache>
解析后的结果存储在 Configuration
的 caches
属性中,该属性定义如下
/** 容器:存放 Mapper.xml 中的 <cache> 构建的 Cache **//** key:为 Mapper.xml 中的 namespace **/protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
<resultMap>
解析后的结果存储在 Configuration
中的 resultMaps
属性中,该属性定义如下
/** 容器:存放 Mapper.xml 中的 <resultMap> 构建的 ResultMap 对象 **//** key 通常为:namespace + "." + id【<resultMap id=""> 中的id属性值】 **/protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
<select|insert|update|delete>
等标签的解析会由新的对象 XMLStatementBuilder
进行解析,解析后的结果存储在Configuration
中的 mappedStatements
属性中,该属性定义如下:
/** 容器:存放 Mapper.xml 文件中 <select|delete|update|insert> 标签的解析数据 **//** key = namespace + <select|delete|update|insert id=""> id 属性 = Mapper.java 全类名 + <select|delete|update|insert id=""> id 属性 **/protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection").conflictMessageProducer((savedValue, targetValue) ->". please check " + savedValue.getResource() + " and " + targetValue.getResource());
针对 xml 文件的解析,都是解析 <xxx>
标签,然后根据解析信息构建对应的 Java 对象,最终把这些数据填充到 Configuration
对象属性中。
更多解析细节,自行翻阅相关源码
mapper class 绑定 xml 文件数据时,同时解析注解
在 mybatis 中,除了能够在 xml 文件中配置数据,如:sql数据通过 <select|insert|delete|update>
等标签,缓存通过 <cache>
标签进行配置,同样的这些配置信息也支持有注解配置,该注解配置可以配置在相应的 mapper class 文件中。
来看一个 mapper class 的文件定义,代码如下:

如上述代码 @Select
对应的xml文件中的 <select>
,@CacheNamespace
对应 xml 文件中的 <cache>
更多配置,参考 mybatis 官网,或者 mybatis 源码
从语义上来说,注解配置和xml配置并没有区别,区别在于声明的方式,一个 xml 标签,一个java代码注解
区别还在于解析构建类的不同,xml 解析在 XMLStatementBuilder
中完成,注解解析在 MapperAnnotationBuilder
中完成。
来看一下注解解析代码 MapperAnnotationBuilder#parse

如上述代码,通过解析注解完成相关配置信息的读取,如:缓存配置,SQL等。
同样的相关解析后的数据和 xml 解析后的数据一样,并存储在 Configuration
对应的容器中。
总结
xml 文件关于 sql 的解析或者标签的解析和 mapper class 关于注解式sql等解析方式不同。
xml 中关于 sql 的解析,在 XMLStatementBuilder
中完成。
mapper class 中关于 sql 的解析在 MapperAnnotationBuilder
中完成。
虽然 xml 和 注解的配置形式不同,但是他们所表达语义是相同的,解析后对应的 java 对象结构也是相同,这些解析数据,会被存放在 Configuration
对象中。
<mappers>
标签解析完 xml 文件和关联的 mapper class 文件后,Mybaits 中 Configuration
对象内容如下:

End




