手撕JAVA(三十一)手撕Mybatis底层源码

手撕JAVA(三十一)手撕Mybatis底层源码

以上是一个标准的原生mybatis的工作流程,最关键的步骤是:

1.创建SqlSessionFactory

2.获取SqlSession

3.获取动态代理对象(mapperProxy)

3.执行方法

本文将按照以上一个mybatis的标准工作流程来拆解mybatis的底层源码。

开始阅读源码之前,先建立三个概念,不然会对阅读造成极大障碍:
1.mybatis有四大对象:executor、StatementHandler、ParamterHandler、ResultHandler

2.mybatis底层封装的是JDBC,其实底层与数据库交互的仍然是原生的JDBC

3.mybatis以xml配置文件来完成开发者与框架的交互,所以整个流程其实就是对配置文件的不断解析与包装。

1.创建SqlSessionFactory

返回一个DefaultSessionFactory,里面包含一个configuration

创建SqlSessionFactory其实就是将xml中的配置文件解析出来,存入configuration类中去。

mybatis的xml配置文件有两类:

1.全局配置文件:用来做全局配置

2.是mapper配置文件:用来写SQL

具体过程就是调用各种解析器去解析这两类xml中的标签

configuration类中的属性其实就是包含了配置文件中各种可能出现的标签

手撕JAVA(三十一)手撕Mybatis底层源码

configuration的成员变量中一个名叫mappedStatements的Map中以KV对的形式存放有mapper.xml的解析结果,key是sql标签中的id值,value是MappedStatement对象

手撕JAVA(三十一)手撕Mybatis底层源码

一个MappedStatement对象就是mapper.xml中一个sql标签的解析结果。

手撕JAVA(三十一)手撕Mybatis底层源码

获取SqlSession

返回DefaultSqlSession,里面包含configuration和executor

获取SqlSession这其实就是根据configuration来创建executor

executor会在这一步被创建,并根据配置文件中的配置解析结果被层层包装。

手撕JAVA(三十一)手撕Mybatis底层源码

获取mapperProxy

configuration中除了mappedStatement外还有个重要的属性——mapperRegistry。

mapperRegistry中包含一切与mapper动态代理相关内容。其中的knowMappers属性

是以KV对的形式存储了每个mapper接口及其MapperProxyFactory。

mapperProxyFactory是用于生产代理对象的工厂类。

手撕JAVA(三十一)手撕Mybatis底层源码

之所以每个mapper都会有单独的一个mapperProxyFactory,而不使用一个总的工厂类来生产代理对象是因为:

1.需要将xml中的sql标签与mapper的方法做关联。这样才能实现在invoke接口的method的时候执行相应的sql标签中的SQL内容。

2.两者的映射关系存放在mapperProxyFactory中的methodCache中。

3.具体封装过程为在mapperProxyinvoke方法中将method封装为一个新的cacheMethod类放入mapperProxyFactorycacheMethod中。

备注:其实cacheMethod类中有三个属性:1.接口 2.

mapperProxyFactory的源码:

封装两个属性:

  1. 对应mapper接口
  2. mapper接口方法和xml文件SQL标签的映射关系map

手撕JAVA(三十一)手撕Mybatis底层源码

mapperProxy的源码:

手撕JAVA(三十一)手撕Mybatis底层源码

执行方法

总体流程

executor负责执行、其实是调用的statementHandler

statementHandler负责预编译、参数处理,其实是调用的ParamterHandler和ResultsetHandler

ParamterHandler负责参数处理、ResultsetHandler负责JAVA类与数据库类之间的映射。     

手撕JAVA(三十一)手撕Mybatis底层源码

详细流程

1.调用代理对象方法,

首先在mapperProxy中将所调用方法封装为cacheMapperMethod对象。改对象中包含

应接口的引用、当前所调用方法的引用、configuration以及sqlSession的引用。

手撕JAVA(三十一)手撕Mybatis底层源码

2.交给executor执行:

代理对象又调用sqlSession中的executor去执行。在执行前会先通过method名字去configuration中拿到对应的MappedStatement.MappedStatement中包含xml中一个SQL标签的全部信息。然后会处理参数调用之前看过的参数处理流程的源码,单个(包括单实体类)就返回,多个就封装为map。

手撕JAVA(三十一)手撕Mybatis底层源码

3.判断缓存

在真正执行之前还会判断本次查询在缓存中是否存在。存在的话直接去缓存中拿,不存在的话executor再继续往下执行。

手撕JAVA(三十一)手撕Mybatis底层源码

4.底层调用JDBC

最后executor底层其实就是封装的原生JDBC的statement等组件。

手撕JAVA(三十一)手撕Mybatis底层源码

流程总结

1.将配置文件解析为Configuration对象,创建一个DefaultSqlSessionFactory对象

      里面包含Configuration

2.创建一个DefaultSqlSession对象

      里面包含Configuration、executor

      1.拿到Mapper接口对应的MapperProxy

      2.执行增删改查方法

调用DefaultSqlSession来执行

         DefaultSqlSession调用自己里面的executor来执行

                  创建Statementhandler、ParameterHandler、ResultHandler

                          Statementhandler负责预编译,

                 statementhandler调用ParameterHandler来设置参数、

                 调用ResultHandler来封装结果(做数据库与JAVABean的映射)