MyBatis binding模块分析

我们在 MyBatis初始化阶段 中学习到了MyBatis初始化的流程,我们主要了解了MyBatis在初始化阶段把核心的配置文件以及Mapper文件全部读取到了Configuration之中,那么我们是如何调用它的呢?我们先看看我们之前是如何使用的
在这里插入图片描述

我们直接通过了SqlSession获取到了我们所需的Mapper类,但是我们都知道我们在MyBatis中所有的Mapper都只有接口,没有实现类的,那么它是如何取到的呢?我们直接看其中的getMapper方法。
在这里插入图片描述

我们发现是直接从我们的Configuration类中读取的
在这里插入图片描述

这是在什么地方注入的呢?我们还记得我们的 MyBatis初始化阶段 中的最后面,就是当我们的XMLMapperBuilder解析完Mapper文件后,我们就将一些信息放入Configuration之中。
在这里插入图片描述
在这里插入图片描述

这里就是将我们的Mapper文件信息填充到了Configuration之中,就是我们namespace内中的内容,也就是我们Mapper的接口全限定名
在这里插入图片描述
在这里插入图片描述

然后直接注意了,我们再回到刚刚我们getMapper的地方
在这里插入图片描述

这里我们又把我们在读取配置文件时添加的信息,在这里我们使用的时候取了出来,然后通过了动态代理的方式来使用的,所以我们之所以可以直接通过Mapper接口就可以操作数据库,是因为我们在MyBatis初始化时读取了配置文件,并且在这里使用了动态代理
在这里插入图片描述




这里我们既然使用到动态代理,那我们就看看我们binding模块中是如何使用动态代理的,首先我们需要了解一下几个类的作用

  • MapperRegistry: Mapper接口和对应代理对象工厂的注册中心
  • MapperProxyFactory: 用于生成Mapper接口动态代理的实例对象
  • MapperProxy: 实现了InvocationHandler接口,它是增强Mapper接口的实现
  • MapperMethod: 封装了Mapper接口中对应方法的信息,以及对应的SQL语句的信息,它是Mapper接口与映射文件中SQL语句的桥梁

MapperRegistry

首先上述的MapperRegistry我们已经见到了,就是我们Configuration中的MapperRegistry,我们MyBatis初始化时读取配置文件就是将我们的Mapper的一些信息,通过addMapper存储在其中,然后我们在使用时,通过getMapper从其中取得
在这里插入图片描述
在这里插入图片描述


MapperProxyFactory

我们在注册的时候,就是以MapperProxyFactory进行包装后进行存储的,如下:
我们

我们我们看到Proxy.newProxyInstance,如果了解 Jdk动态代理 的话,就非常清楚方法其中的含义
在这里插入图片描述

Proxy.newProxyInstance方法参数注解如下,我们可以看到第三个参数就是我们实现方法逻辑的代理类,然后我们就可以进行查看其MapperProxy代理类
在这里插入图片描述

这里就是实现了Jdk的InvocationHandler来实现的动态代理,我们继续查看其invoke方法
在这里插入图片描述

在invoke方法中,我们就会发现它会先判断是否是Object的方法,如果是就不进行代理,否则的话它会从缓存中去拿 MapperMethod,如果缓存中没有的话就会创建一个 MapperMethod,创建后也会存储缓存之中
在这里插入图片描述


MapperMethod

我们来看看MapperMethod里面到底有些啥,它主要有两个变量,我们来具体看看,首先看看第一个变量
在这里插入图片描述

里面的第一个变量SqlCommand是有内部类进行实现的,里面也是有两个变量,第一个变量就是指我们的Mappe文件中的namespace + sql语句的id,这样就可以唯一定位到我们一个Mapper文件中的一个SQL语句了,第二个参数就是我们SQL语句的类型,如插入呀,还是查询呀
在这里插入图片描述
在这里插入图片描述

然后我们继续看看第二个参数 method,它也是有内部类进行实现的,它里面主要是记录的是Mapper接口文件中方法的返回类型呀,传入参数解析器等等
在这里插入图片描述
在这里插入图片描述

我们发现我们的MapperMethod里面既存储了有关Mapper接口的信息,有存储了有关Mapper.xml的信息,所以说它是Mapper接口与映射文件中SQL语句的桥梁。



现在我们得到了MapperMethod,我们来看看它是怎么执行的
在这里插入图片描述

我们在执行时,首先会通过SQL语句的类型,再加上Mapper接口里的返回类型,来判断需要执行的方法。
在这里插入图片描述

然后我们通过命名空间(就是我们的 namespace + id),和参数就可以执行其方法了,我们注意看会发现,最后原来是由我们的 SqlSession 执行的
在这里插入图片描述




上述就是我们发现原来我们使用的Mapper,我们针对Mapper接口进行编程,我们的MyBatis最终还是会通过动态代理帮我们转为了使用SqlSession去执行了
在这里插入图片描述

所以上述代码,其实最终就是由下面这样代码进行执行。
在这里插入图片描述