Mybatis源码解析

Mybatis是我们在项目开发中用的比较多的一个ORM框架,Mybatis通过xml配置的方式可以动态的编写我们的sql,那Mybatis是如何去解析的呢

Mybatis解析配置文件

我们在使用Mybatis的时候通常需要去配置一些XML文件,Mybatis通过解析XML文件来获取数据库的连接数据以及sql,我们来看下具体是如何解析的

我们在使用Mybatis来操作数据库的时候通常需要SqlSessionFactory来进行操作,我们先来看下具体的代码

package com.mybatisdemo;

//import com.mybatisdemo.entity.Account;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.Reader;

public class MybatisDemo {
    public static void main(String[] args) {
        String resource = "mybatis-config.xml";
        Reader reader;
        try {
            //将XML配置文件构建为Configuration配置类
            reader = Resources.getResourceAsReader(resource);
            // 通过加载配置文件流构建一个SqlSessionFactory  DefaultSqlSessionFactory
            SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);
            // 数据源 执行器  DefaultSqlSession
            SqlSession session = sqlMapper.openSession();
            try {
                // 执行查询 底层执行jdbc
               Account account = (Account)session.selectOne("com.mybatisdemo.mapper.AccountMapper.selectById", 1);
                System.out.println(account);
                session.commit();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                session.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面我们通过构建一个Reader对象然后将Mybatis配置文件传入进去,通过SqlSessionFactoryBuilder来构建一个SqlSessionFactory

那么它是通过build()方法来进行构建的,我们可以直接进入到这个方法里看

在这个方法里面可以看到它直接创建了一个XMLConfigBuilder对象,那么这个对象就是用来解析我们的Mybatis配置文件的
在这里插入图片描述
这个对象是继承了BaseBuilder,那么除了这个对象是继承了BaseBuilder之外,还有很多的对象继承了这个BaseBuilder对象,他们分别处理不同的业务

我们可以看下都有哪些对象继承了它
在这里插入图片描述
这几个对象分工很明确,我们可以看看这几个类具体是处理什么业务的

继承类作用
XMLMapperBuilder主要就是用来解析写sql的XML文件
SqlSourceBuilder主要就是用来解析sql语句的
XMLConfigBuilder主要就是用来解析Mybatis全局配置文件的
XMLStatementBuilder主要就是解析映射文件的条件节点
XMLScriptBuilder用来解析脚本的
MapperBuilderAssistant也是用来解析Mapper文件的

那么XMLConfigBuilder在构建的时候就初始化了一个XPathParser对象
在这里插入图片描述
这个对象就是用来解析XML文件的,这个是Mybatis专门提供的,其实就是对XPath的一个封装

在对象创建完成之后,就调用parse()方法开始解析了
在这里插入图片描述
在这个解析方法里面就会开始解析Mybatis全局配置的节点
在这里插入图片描述
它这里调用parser.evalNode()方法就是获取到了Mybatis全局配置文件的节点
也就是这个节点
在这里插入图片描述
那我们可以继续进入到parseConfiguration()方法里

在这个方法里可以看到它开始解析这里面的各个节点

在这里我们需要看下解析Mapper文件的这个方法
在这里插入图片描述
我们可以进入到这个方法里

这个方法里会去循环mapper节点(Mybatis全局配置文件里的mapper节点就是配置的写Mapper文件的路径)

在这个循环里会根据路径来获取Mapper文件
在这里插入图片描述

这个里的Mapper文件通常就是只我们的那个写接口的java文件 ,Mapper映射文件就是只写Sql的XML文件

我们可以继续进入到addMappers()方法里,最终会来到MapperRegistry这个类里的addMappers()方法

在这里插入图片描述
这个方法里会根据路径获取所有的Mapper文件的Class,然后再循环Class对象并添加到Map里去
在这里插入图片描述
存放完了之后就会去解析Mapper映射文件
在这里插入图片描述
我们可以进入到这个解析方法里来

这个方法里调用了loadXmlResource()方法

这个方法里就是根据之前解析的Mapper文件的路径和名称来获取Mapper映射文件
在这里插入图片描述
它会根据Mapper文件的后缀替换成xml的,也就是我们再写xml映射文件的时候为什么要和接口的路径保持一致了

在获取到Mapper映射文件之后就会,就会把文件交由XMLMapperBuilder对象来解析了
在这里插入图片描述
我们可以进入到parse()方法里

在这个方法里它会解析Mapper映射文件的各个节点
在这里插入图片描述
然后在解析的过程中,我们来看下是如何解析我们的select、insert、update、delete这个节点的

我们可以进入到这个方法里可以看到调用了buildStatementFromContext()方法来解析这些节点的

最后它会将这些节点解析成XMLStatementBuilder类
在这里插入图片描述
在这里可以看到解析的时候是直接调用了parseStatementNode()方法

我们可以继续进入到这个方法里

在这个方法里面它会将映射文件的每个节点全部解析都这个SqlSource里,我们可以看看这个SqlSource对象
在这里插入图片描述
这个SqlSource对象有多个对象继承,我们可以直接选择DynamicSqlSource这个对象
在这里插入图片描述
进入到这个对象里可以看到对象里有个SqlNode
在这里插入图片描述
它会将每个XML里的节点解析成一个SqlNode对象

rootSqlNode就是最外层的节点,如果里面还有其他的节点的话,比如if、where等节点,它会把里面的节点也解析成一个SqlNode,然后由根节点的SqlNode指向子节点的SqlNode

这个SqlNode有多个类实现,我们可以看下比较重要的几个

类名作用
MixedSqlNode这个对象里面有个集合,主要是用来存放各个sqlNode节点的
WhereSqlNode主要封装where节点
IfSqlNode主要封装if节点
TextSqlNode主要是用来封装不带任何拼接条件的sql语句
ForEachSqlNode主要是用来封装forEach节点
TrimSqlNode主要是用来封装trim节点
ChooseSqlNode主要是用来封装choose节点

在这里插入图片描述
就像是一个链表一样将各个节点串起来

再把解析后的各个节点封装到MappedStatement对象里,然后添加到configuration对象里

到这里整个配置文件就就解析完了

Mybatis操作数据解析

在调用SqlSession里的方法的时候,实际上它底层是直接通过Executor对象来调用的
在这里插入图片描述
这个Executor对象我们称为执行器

Mybatis为我们提供了五个执行器

类名作用
SimpleExecutor这个主要是用于执行单条数据操作
ReuseExecutor主要是用于不会重复解析sql
BatchExecutor主要是用于执行批量数据操作
BaseExecutor上面的三个类继承了BaseExecutor,这个执行器主要用于一级缓存
CachingExecutor这个主要是用于Mybatis的二级缓存

在我们通过SqlSessionFactory调用openSession()方法的时候,其实这个方法里就给我们初始化了我们所需要的执行器
在这里插入图片描述
我们可以进入到这个方法里看看
在这里插入图片描述
在我们调用查询方法
在这里插入图片描述
底层就会直接调用执行器的查询方法
在这里插入图片描述
在调用这个查询方法之前,它首先会去根据id获取对应的MapperStatement,上面我就讲过了,映射文件解析的节点信息会直接封装到MapperStatement里面

我们可以进入到这个query()方法里看看

这个query()方法有多个类实现了
在这里插入图片描述
我们直接进入到CachingExecutor里面,这个类我在上面就说了主要用来处理二级缓存的,Mybatis在调用查询的时候会从二级缓存里查询

进入到这个方法里后,我们可以看到它首先获取解析我们的sql语句
在这里插入图片描述
我们可以进入到这个getBoundSql()方法里看看

这个方法里就通过SqlSource对象来获取对应的sqlNode,在上面就说了,Mybatis会把映射文件解析封装到一个SqlSource对象里
在这里插入图片描述
在这个方法里会去调用每个sqlNode节点的apply()方法
在这里插入图片描述
通过一个一个节点调用,然后条件判断,将sql拼接起来

那么拼接完之后还要去做参数的替换

这里调用了parsr()方法来进行参数替换
在这里插入图片描述
解析完sql语句之后会去创建一个缓存的key
在这里插入图片描述
创建完之后就直接调用了query()方法来查询了

我们可以进入到这个方法里看看

这个方法里它首先会从二级缓存里查询
在这里插入图片描述
如果二级缓存里没有就会直接从走sql查询了
在这里插入图片描述
queryFromDatabase()这个方法就是直接从数据库里查询数据

我们可以继续进入到这个方法里看看

这个方法里在调用了doQuery()方法,这个方法有4个执行器实现了,我们直接进入到SimpleExecutor执行器里
在这里插入图片描述

在这个方法里面调用了prepareStatement()方法在这里插入图片描述
那么这个方法里就是去获取连接然后获取Statement对象,最后设置参数

最后调用query()方法去执行sql
在这里插入图片描述
我们可以进入到这个query()方法里
在这里插入图片描述
最后将查询出来的结果集进行封装

Mybatis插件详解

Mybatis插件主要是为了对Myatis四大核心对象进行增强—Executor、ParameterHandler、ResultSetHandler、StatementHandler

那么我们在配置插件的时候只需要在Mybatis文件里添加一个plugin节点就行了

 <plugins>
        <plugin interceptor="com.mybatisdemo.plugins.ExamplePlugin" ></plugin>
 </plugins>

Mybatis会将这个插件添加到一个执行链里

我们可以在Configuration对象里看到这个执行链对象
在这里插入图片描述
那么这个插件在初始化执行器对象的时候就会为其进行增强
在这里插入图片描述
我们可以进入到这个puginAll()方法里来

这个方法里主要是调用了plugin()方法,他就会直接调用我们自己重写的这个plugin()方法
在这里插入图片描述
这里我重写的这个方法里没有写任何的东西

这里就调用了wrap()方法

我们可以进入到这个wrap()方法里看看

这里其实就是给我们的执行器做了动态代理
在这里插入图片描述
那么在实际调用的时候就会来到这个Plugin对象里的invoke方法
在这里插入图片描述
在这个invoke方法里,它会直接调用intercept()方法,最终就会来到我们自己重写的那个方法里面
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值