一、前言

Mybatis 全局配置可以通过 XML 构建,也可以编写 Java 代码实现。因为 Mybatis 使用 Configuration 对象保存解析后的信息。
Mybatis 的 org.apache.ibatis.session.Configuration 的对象承载太多的配置信息。比如:
Configuration.png
还有很多,就不一一列举。
下面进行 Mybatis 关于配置文件解析。以下分析只贴最核心的源码,至于里面的解析细节,待有余力之际再做分析吧。

二、解析核心代码XMLConfigBuilder.png

2.1 解析 Properties 元素

XMLConfigBuilder_properties.png

2.2 别名注册器

根据标签值 type 获取 Class 信息,并调用 typeAliasRegistry.registerAlias 注册 API 添加别名映射相关信息。
XMLConfigBuilder_typealias.png

2.3 拦截器

XMLConfigBuilder_plugin.png

2.4 解析 Environment

XMLConfigBuilder_environments.png
在这里通过配置信息实例化事务工厂 TransactionFactory 以及数据源 DataSource 。并作为入参通过 build() 方法构建 Environment

2.5 类型处理器

XMLConfigBuilder_typehandler.png

2.6 解析 Mapper

XMLMapperBuilder_parse_mapper.png

2.6.1 ResultMap 解析

ResultMap 解析比较复杂,根据 XML 配置文件构建 ResultMapping 对象。解析结果如下

对象字段映射

  1. <resultMap id="BaseResultMap" type="blog">
  2. <id column="bid" property="bid" jdbcType="INTEGER"/>
  3. <result column="name" property="name" jdbcType="VARCHAR"/>
  4. <result column="author_id" property="authorId" jdbcType="INTEGER"/>
  5. </resultMap>

ResultMap_object.png

一对多

<resultMap id="BlogWithCommentMap" type="BlogAndComment" extends="BaseResultMap" >
  <collection property="comment" ofType="com.domain.Comment">
    <id column="comment_id" property="commentId" />
    <result column="content" property="content" />
  </collection>
</resultMap

XMLConfigBuilder_resultmap.png

2.6.2 解析 select|insert|update|delete XML 标签

增、删、改、查等 XML 元素会被解析为 org.apache.ibatis.mapping.MappedStatement
对象,并将解析后的对象放入 Configuration Mybatis 配置类中。
MappedStatement_code.png
MappedStatement_detail2.png

2.6.3 解析 SqlSource

SqlSource 解析是非常重要,这一步是在 org.apache.ibatis.builder.xml.XMLStatementBuilder#parseStatementNode() 方法内触发解析,
最终由 XMLScriptBuilder#parseScriptNode() 完成解析。
通过源码简单分析解析流程:

#1 触发 SQL 解析动作

参数 contextXNode 类型对象,内部包含 XML 定义的信息。
XMLStatementBuilder#parseStatementNode.png
XML_Context_parameters.png
createSqlSource() 方法会创建 XMLScriptBuilder ,并用它完成解析动作。

#2 XMLScriptBuilder

XMLScriptBuilder#parseScriptNode.png
parseDynamicTags() 是完成 SQL 解析的核心方法。

#3 SqlNode 节点解析

XMLScriptBuilder#parseDynamicTags.png
我们可以从一条在 XML 定义的 foreach 语句看看最终解释出来的对象是什么:
Select_foreach.png
Sqlsource_detail.png
由上图可知,我们在 XML 所定义的一条 SQL 语句被分段解析成三个对象,分别是

  • StaticTextSqlNode
  • ForEachSqlNode
  • StaticTextSqlNode

它们分别存储其中一段 SQL 内容。select * from blog where bid in 这段内部没有占位符,所以是属性静态文本,不需要做任何改动,但是 <foreach> 就不一样了,他需要遍历入参,所以不同 SqlNode 会根据自身条件对应相应的解析动作。而这个解析动作就是 SqlNode 接口定义的 apply(DynamicContext) 方法。
Different_Text_SQL_NODE.png

SQLNode 继承体系:

SqlNode.png
SqlNode 的实现类拥有能解析
而与节点所对应的是不同的 NodeHandler,它属于 XMLScriptBuilder 内部类。

NodeHandler 继承体系:

NodeHandler.png
SqlNode 节点的创建是由 NodeHandler 完成。
显然,经过以上处理器解析到的 SqlSource 对象,而 SqlSource 也有不同的类型。

SqlSource 继承体系:

SqlSource.png
Mybatis 一般在 DynamicSqlSourceRawSqlSource 做选择,源码如下:
XMLScriptBuilder#parseScriptNode.png
至此,我们简单通过源码了解了 SqlSource 创建过程,从它又引出了 Mybatis 自定义标签(如 <where><trim> 等等)的解析过程。

小结
  • XML SQL 解析是在程序启动时完成,使用 MixedSqlNode 封装已解析的 SqlNode 对象,并把 SqlSource 对象添加到 MappedStatement 对象中,后续我们可以直接通过 getBoundSql(Object) 获取真实可执行的 SQL 语句。
  • 我们也可以实现自定义的XML/注解解析器。详见

    三、总结

  • Mybatis 配置解析是由 org.apache.ibatis.builder.xml.XMLMapperBuilder 完成的。

  • Mybatis 可以通过配置类改变 Mybatis 运行时行为。
  • 配置类的解析包含Mapper文件的解析。
  • Mapper 文件解析
    • ResultMap 会以 namespace + id 为 key 值放入配置类 ConfigurationresultMaps Map集合。
    • SELECT|INSERT|DELETE|UPDATE 类型标签被解析为 MappedStatement 对象并放入配置类 ConfigurationmappedStatements Map集合对象。key 同样为 namespace + id。
  • Configuration 这个类非常重要,它包含了 Mybatis 所有信息。SqlSessionFactory 会话工厂会根据该配置类创建 SqlSession 连接会话。