MyBatis初始化阶段

MyBatis主要有三大核心流程

  • 初始化阶段: 读取XML配置文件和注解中的配置信息,创建配置对象,并完成各个模块的初始化的工作
  • 代理阶段: 封装iBatis的编程模型,使用mapper接口开发的初始化工作
  • 数据读写阶段: 通过SqlSession完成SQL的解析,参数的映射、 SQL的执行、结果的解析过程

这里我们主要来说一说我们MyBatis的初始化阶段,也就是我们MyBatis进行配置加载的阶段,我们看看我们MyBatis是如何把我们的配置文件以及Mapper文件进行加载的。
MyBatis初始化阶段
Configuration: Mybatis启动初始化的核心就是将所有xml配置文件信息加载到Configuration对象中, Configuration是单例的,生命周期是应用级的

MyBatis初始化阶段
MyBatis初始化阶段



Configuration

从上图中,我们可以发现其实我们MyBatis初始化的阶段就是为了创建我们的Configuration,首先我们需要将我们的MyBatis的核心配置文件给加载到Configuration中去。


我们会发现我们在MyBatis配置文件中配置的所有信息,也就是我们的 MyBatis配置 中介绍的所有配置信息,我们在Configuration类中都可以找到对应的地方。
MyBatis初始化阶段



XMLConfigBuilder

我们来看看我们在 初识MyBatis 中测试MyBatis的代码


我们发现其就使用到了我们的 建造者模式 ,其实我们MyBatis在初始化阶段很多地方都使用到了建造者模式,我们也介绍过建造者模式的特点,注重的是部件构建的过程,建造者模式是通过一步一步地精确构造创建一个复杂的对象,刚好符合我们每个人的配置文件可能有所不同。
MyBatis初始化阶段

我们来看看它是如何进行解析MyBatis的配置文件的
MyBatis初始化阶段

我们发现它会先判断下这个配置文件是否已经加载过了,若是没有的话,我们就找到其根节点进行解析
MyBatis初始化阶段
MyBatis初始化阶段

进入其解析方法后,发现它就是一一解析我们配置文件中的各个节点
MyBatis初始化阶段

我们这里以解析properties节点为例,我们会发现有没有子节点,我们properties也可以直接将一些信息用子节点配置在里面的,然后再取一些节点里设置属性信息,判断有没有,有的话进行加载,最后是会将其加载到Configuration之中去的。
MyBatis初始化阶段



XMLMapperBuilder

上述看完了XMLConfigBuilder加载我们的MyBatis配置信息,这里我们再来看看我们的XMLMapperBuilder是如何加载我们的Mapper文件信息的。


我们的Mapper文件信息,也是会配置在MyBatis配置文件中的,我们之前在 MyBatis配置 还介绍过好几种方法,如下:
MyBatis初始化阶段

既然在MyBatis配置文件中,那么肯定会被我们刚刚说的XMLConfigBuilder所解析
MyBatis初始化阶段

这里我们就看一种我们平常最经常用的,看看其是如何解析的。
MyBatis初始化阶段

这里它也是会先判断下文件是否已经加载过了,若是没有的话,我们就找到其根节点进行解析
MyBatis初始化阶段
MyBatis初始化阶段

进入其解析方法后,发现它就是一一解析我们配置文件中的各个节点,然后加入到我们的Configuration中去
MyBatis初始化阶段


由于这里我们之前介绍过 MyBatis 缓存MyBatis缓存模块分析 ,所以这里我们就以解析缓存为例


里面就是解析 <cache> 标签里面的属性,我们在 MyBatis 缓存 几乎已经都介绍过了,也说过如何配置,就是一个之前没有说,它就设置了缓存的类型,我们在 MyBatis缓存模块分析 中介绍了好几种,这里就是可以配置其类型,它默认的就是没有通过装饰模式修饰的最基础的缓存类。最后在通过我们辅助类builderAssistant来加入到我们的Configuration之中
MyBatis初始化阶段

它使用到了建造者模式进行创建一个缓存对象,并且我们知道这配置的是二级缓存,我们的二级缓存是通过namespace进行区别的
MyBatis初始化阶段

所以它是一个以键值对的形式进行存储,就是一个Map
MyBatis初始化阶段
MyBatis初始化阶段




这里我们再来看一看解析 resultMap 标签,因为这个标签我们在Mapper文件中使用的频率非常的高
MyBatis初始化阶段

我们在一个Mapper文件中可能有多个resultMap,所以这里我们需要遍历的去解析
MyBatis初始化阶段

我们会先解析一些resultMap里面设置的一些属性,这里很多我们都使用过,如下
MyBatis初始化阶段
MyBatis初始化阶段

解析完resultMap标签里的属性,我们再看看其中的子标签,如
MyBatis初始化阶段
MyBatis初始化阶段
MyBatis初始化阶段

我们知道resultMap里面肯定有多行子标签,它会去判断是构造器、还是鉴别器,还是我们用来映射字段信息的
MyBatis初始化阶段

最后我们会把所有解析resultMap的结果都会有我们的辅助类builderAssistant进行处理
MyBatis初始化阶段

里面通过了建造者模式生成出ResultMap,然后添加到Configuration之中。
MyBatis初始化阶段
MyBatis初始化阶段

它的key是有Mapper的namespace命名空间加上了resultMap的id组成的,这样就可以唯一对应的一个ResultMap
MyBatis初始化阶段

我们来看看我们用于存储resultMap信息的数据结构ResultMap,就是保存上述我们解析完得到结果的类


我们可以看到该数据结构中,保存了resultMap中可以设置的所有属性值,如id、所要映射的Java对象类型,还有一些鉴定器等等,我们还发现里面还有一些分类的List,里面保存就ResultMapping的数据结构主要是为了存储resultMap下的行信息
MyBatis初始化阶段

如我们经常用到的一些行属性,以及一对多时使用到的属性
MyBatis初始化阶段



XMLStatementBuilder

刚刚我们说了XMLMapperBuilder帮助我们解析了Mapper文件,现在我们Mapper文件中只有SQL语句没有进行解析了,现在我们就主要看看其SQL语句的解析。
MyBatis初始化阶段
MyBatis初始化阶段

里面就是对我们SQL语句中的一些属性进行解析
MyBatis初始化阶段

这里就是对我们SQL语句执行的类型,我们之前说过前两中,就是直接拼接和预编译的区别,这里默认的是预编译设置,第三个就和存储过程有关。
MyBatis初始化阶段
MyBatis初始化阶段

这是判断下我们SQL语句的类型,是增删改查中的哪一种
MyBatis初始化阶段
MyBatis初始化阶段

这里就是为了处理我们include标签引入的 sql 的SQL语句,以及处理我们 selectKey标签等,处理完成后我还需要将其删除,最后我们解析SQL语句,得到SqlSource
MyBatis初始化阶段

里面存储的就是我们处理完后的SQL语句,以及这里占位符需填充的参数
MyBatis初始化阶段
MyBatis初始化阶段

下面就是我们判断是否是 INSERT 语句,是的话,我们又配置了 userGeneratedKeys ,这里我们就会去拿到其生成的主键
MyBatis初始化阶段

最后我们就是将上述得到的结果,全部交由辅助类builderAssistant去处理
MyBatis初始化阶段

里面我们通过了建造者模式生成出MappedStatement,然后添加到Configuration之中。
MyBatis初始化阶段
MyBatis初始化阶段
MyBatis初始化阶段

最后我们在来看看建造者生成的MappedStatement,里面就是封装了一系列信息,有些就是我们上述所介绍的
MyBatis初始化阶段



最后我们要看一下就是我们的Mapper文件解析完成之后,就是我们的XMLMapperBuilder、XMLStatementBuilder处理完成之后,也就是我们的Mapper文件全部解析好了,我们看看之后的操作


我们就将这个的结果也放到Configuration里面,并且还要去注册Mapper接口
MyBatis初始化阶段
MyBatis初始化阶段

最后我们有可能还有解析失败的,所以我们再将解析失败的再尝试解析一下进行处理
MyBatis初始化阶段