通过MyBatis的读取全局配置的时序图,可知 Configuration 的属性 Map<String, MappedStatement> mappedStatements ,以及 属性MapperRegistry(装有接口以及接口的代理工厂的键值对)读取时机以及原理,如图:
mybatis 初始化的过程中,主要是 XML 配置的解析,不同的部分又分别委托给了不同的解析器
解析流程为:
XMLConfigBuilder -> XMLMapperBuilder -> XMLStatementBuilder -> XMLScriptBuilder -> SqlSourceBuilder
XMLConfigBuilder:负责全局的 mybatis-conf.xml 配置解析;
XMLMapperBuilder:负责 sql 配置的 mapper 配置解析;
XMLStatementBuilder:负责 mapper 配置文件中 select|insert|update|delete 节点解析;
XMLScriptBuilder:负责各 sql 节点解析,主要是动态 sql 解析;
SqlSourceBuilder:负责构建 SqlSource;
源码分析:
首先在 XMLConfigBuilder 确定了主要的解析流程:
mapperElement
动态 sql 解析
此外在 mapper 各节点的解析过程中 resultMap 和 sql 节点的解析最为复杂,resultMap 解析主要是 xml 和 反射的处理,有一点繁琐有兴趣可以自己看一下;这里主要讲一下 sql 节点的解析要点;
XMLMapperBuilder中
通过xml配置动态解析
代码中的 LanguageDriver 就封装了动态 sql 的解析规则,通过这个接口也可以使用其他的模版引擎或者解析规则(可以通过配置或者注解指定);
其中 XMLLanguageDriver 主要处理动态 sql,RawLanguageDriver 主要处理静态 sql;
从代码中可以看到最后 LanguageDriver 将 xml 配置解析成了 SqlSource,其结构如下:
RawSqlSource:处理静态sql,去掉xml标签;
DynamicSqlSource:处理动态sql,去掉xml标签;
ProviderSqlSource:处理注解形式的sql;
StaticSqlSource:最终将上面 SqlSource 处理结果中的占位符,替换为 "?",构成真正可执行的sql
其解析的整体流程如下
从图中可以看到 sql 节点的主要解析逻辑就在于 parseDynamicTags,MixedSqlNode rootSqlNode = parseDynamicTags(context);
在看源码之前先看一下 SqlNode 的结构
每个 node 和 sql 节点下的子节点一一对应
这里主要逻辑是首先通过子标签的名字,获取对应的处理器,然后将所有的子标签生成的 SqlNode 合成 MixedSqlNode;
到这里就已经比较清楚了,这个 sql 节点的解析过程使用的是策略模式,整个 sql 节点被封装成 SqlSource,其子节点封装为 SqlNode,每个 Node 的解析行为又封装到 NodeHandler 中;整个流程虽然比较长,但是每个模块都非常的清晰,这里非常值得我们学习;
mapper 动态代理
从上面的代码可以看到,我们只定义一个接口并没有实现类,但是通过动态代理就可以动态生成实现类;在使用 mapper 的时候也是一样的,每次调用mapper方法的时候,都会动态生成一个实现类;