Mybatis 中 Mapper 接口的存储与实现

01、前言

在平常我们写的 SSM 框架中, 定义了 Mapper 接口与 .xml 对应的 SQL 文件, 在 Service 层直接注入 xxxMapper 就可以了

也没有看到像 JDBC 操作数据库的操作, Mybatis 在中间是如何为我们省略下这些重复繁琐的操作呢

这里使用 Mybatis 源码中的测试类进行验证, 首先定义 Mapper 接口, 省事直接注解定义 SQL

Mybatis 中 Mapper 接口的存储与实现

这里使用 SqlSession 来获取 Mapper 操作数据库, 测试方法如下

Mybatis 中 Mapper 接口的存储与实现

02、创建 SqlSession

#1 从 SqlSessionFactory 中打开一个 新的 SqlSession

03、获取 Mapper 实例

#2 就存在一个疑问点, 定义的 AutoConstructorMapper 明明是个接口, 为什么可以实例化为对象?

04、动态代理方法调用

#3 通过创建的对象调用类中具体的方法, 这里具体聊一下 #2 操作

SqlSession 是一个接口, 有一个 默认的实现类 DefaultSqlSession, 类中包含了 Configuration 属性

Mapper 接口的信息以及 .xml 中 SQL 语句是在 Mybatis 初始化时添加 到 Configuration 的 MapperRegistry 属性中的

Mybatis 中 Mapper 接口的存储与实现

#2 中的 getMapper 就是从 MapperRegistry 中获取 Mapper

看一下 MapperRegistry 的类属性都有什么

Mybatis 中 Mapper 接口的存储与实现

config 为 保持全局唯一 的 Configuration 对象引用

knownMappers 中 Key-Class 是 Mapper 对象, Value-MapperProxyFactory 是通过 Mapper 对象衍生出的 Mapper 代理工厂

再看一下 MapperProxyFactory 类的结构信息

Mybatis 中 Mapper 接口的存储与实现

mapperInterface 属性是 Mapper 对象的引用, methodCache 的 key 是 Mapper 中的方法, value 是 Mapper 解析对应 SQL 产生的 MapperMethod

???? Mybatis 设计 methodCache 属性时使用到了 懒加载机制, 在初始化时不会增加对应 Method, 而是在 第一次调用时新增

Mybatis 中 Mapper 接口的存储与实现

05、MapperMethod

MapperMethod 运行时数据如下, 比较容易理解

Mybatis 中 Mapper 接口的存储与实现

通过一个实际例子帮忙理解一下 MapperRegistry 类关系, Mapper 初始化第一次调用的对象状态, 可以看到 methodCache 容量为0

Mybatis 中 Mapper 接口的存储与实现

我们目前已经知道 MapperRegistry 的类关系, 回头继续看一下第二步的 MapperRegistry#getMapper() 处理步骤

Mybatis 中 Mapper 接口的存储与实现

核心处理在 MapperProxyFactory#newInstance() 方法中, 继续跟进

Mybatis 中 Mapper 接口的存储与实现

MapperProxy 继承了 InvocationHandler 接口, 通过 newInstance() 最终返回的是由 Java Proxy 动态代理返回的动态代理实现类

看到这里就清楚了步骤二中接口为什么能够被实例化, 返回的是 接口的动态代理实现类