前言

上篇我们分享了mybatis配置解析和初始化的过程,今天我们接着进入下个阶段。在进入下个阶段前,我想抛一个问题,我们在spring里面直接使用Mapper接口去执行sql语句,这过程中并没有Mapper的实现类,请问mybatis是怎么为我们神奇的完成整个数据读写过程的?今天我们就一起来解密这个过程。

核心运作流程

mybatis源码解析 - 核心流程分析之编程模型构建_第1张图片

要解决篇头提出的问题,我们就得读mybatis的Mapper编程模型这块的源码。

Mapper编程模型调用链路

mybatis源码解析 - 核心流程分析之编程模型构建_第2张图片

注:上图红色字体的调用为调用链路上重点环节

源码分析

根据上面的调用链路,我们先来看看平时使用原生ibatis进行开发的一个简单场景

mybatis源码解析 - 核心流程分析之编程模型构建_第3张图片

我们今天的源码追踪就从sqlSession.getMapper()这句代码开始

mybatis源码解析 - 核心流程分析之编程模型构建_第4张图片

我们在这里调用了getMapper, 请问mapperRegistry中的mapper是在什么时候,哪个位置写入的呢?按照思路想,是不是应该在第一阶段初始化配置才对,那么是在哪个位置写入的?

mybatis源码解析 - 核心流程分析之编程模型构建_第5张图片

继续跟进跟进去看看,里面干了什么事儿..

mybatis源码解析 - 核心流程分析之编程模型构建_第6张图片

截图中的MapperProxyFactory<>是何方圣神?

mybatis源码解析 - 核心流程分析之编程模型构建_第7张图片

由上图我们可以看到MapperProxyFactory这个类实际上是一个代理工厂,由它实际产生代理对象。那个代理对象mapperInterface实际就是我们传入的Mapper接口类对吧?再看看newInstance()方法是什么时候调用的?

mybatis源码解析 - 核心流程分析之编程模型构建_第8张图片

是不是正好是在这个getMapper方法中来调用的!OK看到这里我们知道这个Mapper接口对象是如何产生的了。但是刚才我们看到源码MapperProxyFactory中的代理是对传入的每个业务Mapper增强,那它是如何增强的呢?是否能进一步解决我们篇头提出的问题?玄机就在这个MapperProxy类中

mybatis源码解析 - 核心流程分析之编程模型构建_第9张图片

PlainMethodInvoker对象包装了MapperMethod对象,看来增强的内核在这个里面了,继续深入揭晓答案。

mybatis源码解析 - 核心流程分析之编程模型构建_第10张图片

是不是看到熟悉的身影了?!sqlSession原子的操作了最终就在这里出现了。也就是当我们通过mapper对象调用接口方法时,方法被路由到MapperProxy中,最终通过MapperMethod核心类包装进行当前会话的原子CRUD操作。

OK,看到这里我们基本上可以断言我们篇头提出的问题已经回答一半了,当然要回答好这个问题,我们还需要进一步的深入源码分析,里面的封装还有一整套设计思路和流程。我们下篇继续分析。最后我们再一起来看看SqlCommandType类,在上图execute()方法中,接口方法的识别和sql命令类型的识别全靠这个类的封装

mybatis源码解析 - 核心流程分析之编程模型构建_第11张图片

正因为从mappedStatement中拿到id和sqlCommandType字段的值,才使execute的执行逻辑封装得以实现,而SqlCommandType类就明显封装了这个能力。

最后再归纳一下mybatis的Mapper接口编程模型中这几个核心类

mybatis源码解析 - 核心流程分析之编程模型构建_第12张图片

MapperRegistry : mapper接口和对应的代理对象工厂的注册中心;

MapperProxyFactory:用于生成mapper接口动态代理的实例对象;

MapperProxy:实现了InvocationHandler接口,它是增强mapper接口的实现;

MapperMethod:封装了Mapper接口中对应方法的信息,以及对应的sql语句的信息;它是mapper接口与映射配置文件中sql语句的桥梁,MapperMethod对象不记录任何状态信息,所以它可以在多个代理对象之间共享;

 总结

至此mybatis的Mapper接口编程模型的源码解析就先告一段落,后面在mybatis核心流程的第三阶段中,会展开分享ibatis的sqlSession门面底层的详细设计思路和源码。更多mybatis源码的内容请继续关注!