Mr. Cappuccino的第53杯咖啡——Mybatis源码分析
Mybatis源码分析
- Mybatis源码分析入口
- 1. 读取配置文件
- 总结
- 2. 解析配置文件
- 核心代码(一)
- 核心代码(二)
- 分析parse()方法
- 分析build()方法
- 总结
- 3. 获取SqlSession
- 总结
- 4. 获取mapper代理对象
- 总结
- 5. 使用mapper代理对象执行Sql语句
- 二级缓存
- 一级缓存
- 总结
Mybatis源码分析入口
本文将根据下面这段代码进行源码分析
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<UserEntity> list = mapper.listUser();
System.out.println(list);
sqlSession.close();
1. 读取配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
ClassLoaderWrapper.java

总结
从入口一路点击进去可以发现底层是通过调用java.lang.ClassLoader#getResourceAsStream方法来读取resources目录下的mybatis-config.xml文件,并得到InputStream对象
2. 解析配置文件
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactoryBuilder.java


核心代码(一)
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
XMLConfigBuilder.java

XPathParser.java

可以发现底层是将InputStream对象转换成Document对象,并将Document对象保存至当前类(XPathParser)的document属性中
继续回到上一层,点击进入this()方法
XMLConfigBuilder.java

可以发现this()方法主要是在进行部分属性的初始化,并将XPathParser对象保存至当前类(XMLConfigBuilder)的parser属性中。
关键点:初始化了父类的configuration属性。
核心代码(二)
return build(parser.parse());
分析parse()方法
XMLConfigBuilder.java

- 根据Document对象获取节点为configuration的配置信息,并转换成XNode对象
XPathParser.java

- 将XNode对象解析成Configuration对象
XMLConfigBuilder.java

XMLConfigBuilder.java

点击进入addMappers(mapperPackage)方法
Configuration.java

MapperRegistry.java




从这里可以发现parser.parse()主要是在解析配置文件(mybatis-config.xml),具体过程是根据Document对象获取节点为configuration的配置信息,并转换成XNode对象再解析各个节点,重点部分是mappers节点的解析。
在解析mappers节点的代码中可以发现如果是使用package或class注册mapper可以直接注册mapper接口对象,如果是使用url或者resource注册mapper则需要先解析mapper.xml映射文件后并通过namespace找到所绑定的接口对象再进行注册。
mapper的注册是通过MapperRegistry对象完成的,而MapperRegistry则是Configuration对象里面的一个属性,也就是说所有的配置解析完成后都存放在Configuration对象中。
parser.parse()最终返回Configuration对象。
分析build()方法
SqlSessionFactoryBuilder.java

DefaultSqlSessionFactory.java

从这里可以发现SqlSessionFactoryBuilder将得到的Configuration对象建造成DefaultSqlSessionFactory对象,也就是SqlSessionFactory对象。
总结
SqlSessionFactoryBuilder先是通过XMLConfigBuilder解析配置文件并将解析得到的配置装载到Configuration对象中,再将Configuration建造成DefaultSqlSessionFactory对象。
这里采用了建造者设计模式
BaseBuilder:所有解析器的父类,包含配置文件实例,为解析文件提供一些通用的方法;
XMLConfigBuilder:主要负责解析mybatis-config.xml文件;
XMLMapperBuilder:主要负责解析mapper.xml文件;
XMLStatementBuilder:主要负责解析映射文件中的SQL节点;
Configuration对象核心属性释义:
- MapperRegistry:mapper接口动态代理工厂类的注册中心;
- ResultMap:用于解析mapper.xml文件中的resultMap节点,使用ResultMapping来封装id、result等子元素;
- MappedStatement:用于存储mapper.xml文件中的select、insert、update和delete节点,同时还包含了这些节点的很多重要属性;
- SqlSource:用于创建BoundSql,mapper.xml文件中的sql语句会被解析成BoundSql对象,经过解析BoundSql包含的语句最终仅仅包含?占位符,可以直接提交给数据库执行;
3. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
DefaultSqlSessionFactory.java

Configuration.java


从这里可以看到如果没有设置执行器类型,则会默认使用简单执行器类型
ExecutorType.java

上面枚举类中的三种执行器类型均可通过openSession()传参设置
点击进入openSessionFromDataSource()方法
DefaultSqlSessionFactory.java

openSessionFromDataSource()方法有三个入参:ExecutorType execType(执行器类型)、TransactionIsolationLevel level(事务隔离级别)、boolean autoCommit(是否自动提交)
- 获取TransactionFactory
DefaultSqlSessionFactory.java

TransactionFactory有两种:JdbcTransactionFactory,ManagedTransactionFactory
通过mybatis-config.xml文件进行配置

<transactionManager type="JDBC"/>
这里配置的是JdbcTransactionFactory
- 获取Transaction
JdbcTransactionFactory.java

JdbcTransaction.java

- 根据Transaction和执行器类型获取执行器(核心代码)
Configuration.java

CachingExecutor.java

Mybatis默认使用的执行器是SimpleExecutor,SimpleExecutor的父类是BaseExecutor,BaseExecutor下一共有三个子类也就是三种执行器:BatchExecutor、SimpleExecutor、ReuseExecutor,这三种执行器均可通过传值设置。
cacheEnabled默认值为true,说明Mybatis默认会使用CachingExecutor。进入CachingExecutor类可以发现,CachingExecutor是在上面三种执行器(BaseExecutor)的基础上做了一层包装(装饰器设计模式),先调用CachingExecutor再调用BaseExecutor,是对BaseExecutor类的增强。
cacheEnabled可以通过mybatis-config.xml文件进行配置
<settings><!-- 是否开启二级缓存 --><setting name="cacheEnabled" value="false"/>
</settings>
BaseExecutor是一级缓存(默认开启),默认使用SimpleExecutor,CachingExecutor是二级缓存(默认开启,但还需要做一些额外的配置才能生效)
- 生成DefaultSqlSession

将Configuration、Executor、autoCommit等信息包装成DefaultSqlSession对象,并且返回该对象
总结
openSession()是SqlSessionFactory接口中的一个重载方法,可以配置执行器类型、事务隔离级别、是否自动提交等参数,Configuration负责判断当前使用的执行器(Executor),DefaultSqlSessionFactory最后将Configuration、Executor、autoCommit等信息包装成DefaultSqlSession对象并返回。
这里采用了装饰器设计模式
BaseExecutor是一级缓存(默认开启),BaseExecutor是BatchExecutor、SimpleExecutor、ReuseExecutor三种执行器的父类。
- SimpleExecutor:默认的Executor,每个SQL执行的时候都会创建新的Statement;
- ReuseExecutor:相同的SQL会重复使用Statement;
- BatchExecutor:用于批处理的Executor;
CachingExecutor是二级缓存(默认开启,但还需要做一些额外的配置才能生效)
CachingExecutor:可缓存数据的Executor,用装饰器模式包装了其它的执行器(如BaseExecutor下的三种执行器)
4. 获取mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
DefaultSqlSession.java

Configuration.java

MapperRegistry.java

之前已经对mapper接口进行了注册,这里通过mapper接口类型获取对应的动态代理工厂类(MapperProxyFactory),动态代理工厂类使用JDK动态代理技术生成mapper代理对象并返回该对象。
MapperProxyFactory.java

MapperProxy.java

JDK动态代理技术主要用于拦截和修改方法的调用,在使用mapper代理对象调用mapper接口中的方法时MapperProxy中的invoke方法也会被执行。
总结
根据mapper接口类型从MapperRegistry中获取对应的动态代理工厂类(MapperProxyFactory),动态代理工厂类使用JDK动态代理技术生成mapper代理对象并返回该对象。在使用mapper代理对象调用方法时底层会走MapperProxy中的invoke方法。
这里采用了JDK动态代理设计模式
MapperRegistry:mapper接口动态代理工厂类的注册中心;
MapperProxyFactory:用于生成动态代理的实例对象;
MapperProxy:动态代理回调类;
5. 使用mapper代理对象执行Sql语句
List<UserEntity> list = mapper.listUser();


MapperProxy.java


核心代码
mapperMethod.execute(sqlSession, args);
MapperMethod.java

因为执行的SQL为select,返回值类型为List集合,所以会走executeForMany()方法

DefaultSqlSession.java

这个方法是不是很熟悉,没错,这就是在基于XML方式-原生方式开发用到的方法
List<UserEntity> list = sqlSession.selectList("com.mybatis.mapper.UserMapper.listUser", UserEntity.class);
DefaultSqlSession.java


二级缓存
如果开启了二级缓存则会使用CachingExecutor
CachingExecutor.java

- 获取SQL语句

- 创建缓存key

- 执行查询逻辑



SimpleExecutor中没有query方法,默认走父类(BaseExecutor)
一级缓存
BaseExecutor.java


SimpleExecutor.java

- 初始化RoutingStatementHandler对象
Configuration.java

RoutingStatementHandler.java

- 生成Statement对象
SimpleExecutor.java

2.1. 获取Connection
BaseExecutor.java

JdbcTransaction.java

2.2. 根据不同的StatementHandler创建Statement对象
RoutingStatementHandler.java

BaseStatementHandler.java

Mybatis默认采用PreparedStatementHandler处理器
PreparedStatementHandler.java

2.3. 使用ParameterHandler处理占位符参数
RoutingStatementHandler.java

PreparedStatementHandler.java

DefaultParameterHandler.java

- 执行查询逻辑
RoutingStatementHandler.java

PreparedStatementHandler.java

DefaultResultSetHandler.java

总结
在使用代理对象调用方法时,底层会走MapperProxy中的invoke方法,在执行查询语句时,默认会先从二级缓存(CachingExecutor)中读取数据,如果存在则直接返回,不存在则继续查询一级缓存,如果一级缓存(BaseExecutor)中存在则直接返回,不存在则继续查询数据库,在查询数据库时,总体上使用StatementHandler对象和JDBC进行交互,整个查询流程先是使用ParameterHandler对SQL语句的入参进行处理,待SQL语句被执行完后得到结果集,再使用ResultSetHandler对结果集进行处理并返回。
四大核心接口对象
- Executor(执行器):负责整个SQL执行过程的总体控制;
- StatementHandler(语句处理器):负责和JDBC层的具体交互;
- ParameterHandler(参数处理器):负责PreparedStatement入参的具体设置;
- ResultSetHandler(结果集处理器):负责将JDBC查询的结果映射为Java对象;
StatementHandler
- RoutingStatementHandler:根据StatementType路由到不同的StatementHandler对象;
- SimpleStatementHandler:管理Statement对象并向数据库中推送不需要预编译的SQL语句;
- PreparedStatementHandler:管理Statement对象并向数据库中推送需要预编译的SQL语句;
- CallableStatementHandler:管理Statement对象并调用数据库中的存储过程;
相关文章:
Mr. Cappuccino的第53杯咖啡——Mybatis源码分析
Mybatis源码分析 Mybatis源码分析入口1. 读取配置文件总结 2. 解析配置文件核心代码(一)核心代码(二)分析parse()方法分析build()方法 总结 3. 获取SqlSession总结 4. 获取mapper代理对象总结 5. 使用mapper代理对象执行Sql语句二…...
修改文件格式(查看文件拓展名)
很多时候我们直接把txt文件重命名为xxx.c或者别的文件格式,文件类型依然会是txt,文件名并不会变成我们想要的xxx.c,而是xxx.c.txt,也就是下面这个样子 给大家介绍2种方法去解决这个问题 目录 1.另存为新格式 2.显示文件拓展名 1…...
利用鸿鹄可观测性监控Istio Ingress网关
一、需求描述 在上一篇《利用Vector和鸿鹄搭建微服务应用的可观测性平台》中,阐述了微服务的基本概念、优点及如何利用鸿鹄来处理分布式应用的日志。本文将进一步讨论微服务架构面临的问题、服务网格及鸿鹄处理Istio Gateway的独特优势。 1.1 微服务架构面临的挑战 …...
vscode 前端开发插件 2023
自己记录 安装vscode后必装插件 chinesegit 必装没啥可说 随时更新 1.CSS Navigation CTRL点击类名可跳转到对应样式位置。 如果是scss less的话。css peak插件无法生效 2.GitLens — Git supercharged 可以看到每一行的git提交记录。 3.Auto Rename Tag 可以同步更新…...
使用docker部署Wordpress
文章目录 1.创建网络2.创建volume存储3.拉取镜像4.创建mysql容器mysql修改密码 5.创建wordpress容器6.访问localhost:80就可以直接使用啦 1.创建网络 docker network create --subnet172.18.0.0/24 pro-net2.创建volume存储 # mysql 存储 docker volume create volume_mysql…...
7.31黄金最新行情走势分析及多空交易策略
近期有哪些消息面影响黄金走势?黄金多空该如何研判? 黄金消息面解析:上周有重磅数据美联储加息的消息,黄金受其影响波动比较频繁,总体空间40美金。但这个过程跌宕起伏。收线来看黄金在连续上涨三周后迎来一根小阴十…...
Spring框架——AOP注解方式
目录 Spring框架的AOP技术(注解方式) 通知类型 Spring框架的AOP技术(注解方式) 1. 步骤一:创建JavaWEB项目,引入具体的开发的jar包* 先引入Spring框架开发的基本开发包com.springsource.org.apache.commo…...
Java 日志(Logging)如何创建和捕获日志消息和文件
Java允许我们通过日志记录过程来创建和捕获日志消息和文件。 在Java中,日志记录需要框架和API。Java在java.util.logging程序包中具有内置的日志记录框架。 Java 日志组件 下图显示了Java Logging API(java.util.logging)的核心组件和指定…...
em3288 linux_4.19 lvds+tp调试
一、显示配置\rk3288_linux4.19\kernel\arch\arm\boot\dts\rk3288-evb-act8846.dtspanel {compatible "simple-panel";backlight <&backlight>;bus-format <MEDIA_BUS_FMT_RGB666_1X18>;enable-gpios <&gpio1 24 GPIO_ACTIVE_HIGH>;ena…...
Linux 之 systemctl
systemctl 可以控制软件(一般指服务)的启动、关闭、开机自启动 能被systemctl 管理的软件,一般也称 服务 系统内置服务均可被 systemctl 控制第三方软件,如果 自动注册了 可被systemctl 控制第三方软件,如果没有自动…...
【技巧】通过 CMD 走代理下载 Vue
通过 CMD 走代理下载 Vue 在学习或者工作中,有时上网走的是代理模式,就是在浏览器里面配置代理服务的那种。后来在下载 Vue 组件的时候显示请求超时。此时才发先,浏览器代理只能在浏览器里生效,cmd 中不生效,那该怎么办…...
VSCode C/C++多文件编译配置
多文件编译备忘,带注释的地方都需要注意!!! launch.json文件 {// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid830387&quo…...
Autosar通信入门系列05-聊聊一帧Can/CanFD报文发送时间?
本文框架 1. 概述2. 一帧CAN报文发送时间计算3. 一帧CanFD报文的传输时间计算3.1 标准CAN与CANFD两者间的区别3.2 CANFD报文传输时间计算 1. 概述 本篇我们一起看下一帧Can报文发送需要多长时间,下述文章里我们会首先计算下Can分别对应的字节数,再根据传…...
【phaser微信抖音小游戏开发002】hello world!
执行效果: 将以下代码文本内容,放入到game.js中即可。目录结构如下图 import ./js/libs/weapp-adapter import ./js/libs/symbolGameGlobal.window.scrollTo () > { };//防止真机出错 import Phaser from ./js/phaser//引入Phaservar {windowWidth, …...
2023.07.29 驱动开发DAY6
通过epoll实现一个并发服务器 服务器 #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/epoll.h…...
网工必须掌握的5种组网技术,你会了吗?
作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 目录 一、VLAN技术 1、VLAN是什么? 2、VLAN的作用 ①提高网络安全性 ②提高了网络的灵活性性 ③增强了网络的健壮性 二、D…...
webpack中文文档
基本安装 首先我们创建一个目录,初始化 npm,然后 在本地安装 webpack,接着安装 webpack-cli(此工具用于在命令行中运行 webpack): mkdir webpack-demo cd webpack-demo npm init -y npm install webpack …...
【Linux指令篇】--- Linux常用指令汇总(克服指令繁杂问题)
文章目录 前言🌟一、Linux基本指令🌟二、ls指令🌏2.1.语法:🌏2.2.功能:🌏2.3.常用选项: 🌟三、pwd指令🌏3.1.语法:🌏3.2.功能…...
硬盘的分类
目前常见的硬盘种类主要有以下2种: 机械硬盘(HDD) 机械硬盘(HDD)是一种利用旋转磁盘和读写头来存储和访问数据的存储设备。它由磁盘、读写头、电机和控制电路等组成,磁盘通常是一种铝合金或玻璃材质的圆盘&…...
el-upload批量手动上传,并用form表单校验上传文件
手动上传设置:auto-upload"false" <el-formref"formData"class"formWidth":model"formData"label-width"120px":rules"rules"><el-form-itemlabel"数据"class"uploadClass"required…...
终极指南:在Linux系统上安装与优化Realtek RTL8125 2.5GbE网卡驱动
终极指南:在Linux系统上安装与优化Realtek RTL8125 2.5GbE网卡驱动 【免费下载链接】realtek-r8125-dkms A DKMS package for easy use of Realtek r8125 driver, which supports 2.5 GbE. 项目地址: https://gitcode.com/gh_mirrors/re/realtek-r8125-dkms …...
CANN/asc-devkit原子减法操作
asc_atomic_sub 【免费下载链接】asc-devkit 本项目是CANN 推出的昇腾AI处理器专用的算子程序开发语言,原生支持C和C标准规范,主要由类库和语言扩展层构成,提供多层级API,满足多维场景算子开发诉求。 项目地址: https://gitcode…...
Aspia文本聊天功能:内置即时通讯的远程协助工具
Aspia文本聊天功能:内置即时通讯的远程协助工具 【免费下载链接】aspia Remote desktop and file transfer tool. 项目地址: https://gitcode.com/gh_mirrors/as/aspia Aspia是一款功能强大的远程桌面和文件传输工具,其内置的文本聊天功能为远程协…...
晶振参数深度解读与替代选型实战(55.2MHz 工业级无源晶振案例)
前言作为嵌入式 / 硬件 FAE,日常工作中晶振的参数解读、客户需求替代是高频场景。最近遇到一个典型的工业级宽温晶振客户需求,参数里藏着很多新手容易踩的坑,比如 “负频率” 的误解、负载电容不匹配、宽温范围忽略等问题。本文以客户的55.2M…...
论文查重,重复率高该怎么办?
论文查重高,先别急着想“有没有捷径”。先判断你高到什么程度。10%-20%超线一点:最好处理 这种通常不是“论文废了”,而是局部重复。最常见:文献综述太像参考文献原话理论定义直接搬对策建议全是“加强XX、完善XX、建立XX”方法部…...
VirtualBox虚拟机里Win10远程桌面黑屏?手把手教你改组策略搞定它
VirtualBox虚拟机Win10远程桌面黑屏终极解决方案:从策略组到网络优化的全链路排查 当你正沉浸在VirtualBox虚拟机的Windows 10环境中进行关键开发工作,突然发现远程桌面连接后只剩一片漆黑——这种体验就像在重要会议前突然失声。不同于物理机的远程连接…...
360T7路由器无线中继保姆级教程:5分钟搞定信号扩展,告别WiFi死角
360T7路由器无线中继保姆级教程:5分钟搞定信号扩展,告别WiFi死角 你是否经常遇到这样的困扰:客厅WiFi信号满格,但卧室却时断时续;刷剧正到精彩处突然卡顿;游戏团战时延迟飙升...这些恼人的网络死角问题&…...
PPTXjs终极指南:3分钟学会在浏览器中完美预览PPTX文件
PPTXjs终极指南:3分钟学会在浏览器中完美预览PPTX文件 【免费下载链接】PPTXjs jquery plugin for convertation pptx to html 项目地址: https://gitcode.com/gh_mirrors/pp/PPTXjs 还在为PPT文件兼容性问题烦恼吗?当精心制作的演示文稿在不同设…...
DeepSeek-R1 MoE架构逆向工程报告(基于HuggingFace源码+NCCL trace分析):专家粒度、FFN维度与token路由热力图首次披露
更多请点击: https://kaifayun.com 第一章:DeepSeek-R1 MoE架构逆向工程总览 DeepSeek-R1 是一款基于稀疏混合专家(Mixture of Experts, MoE)架构的大语言模型,其推理与训练行为在公开文档中未完全披露。本章聚焦于通…...
无人机避障新思路:拆解EGO-Planner如何用B样条和“斥力点”省掉ESDF
无人机避障新思路:拆解EGO-Planner如何用B样条和“斥力点”省掉ESDF 当四旋翼无人机在复杂环境中穿行时,传统的避障算法往往需要构建完整的欧几里得符号距离场(ESDF),这就像要求无人机在飞行前必须绘制整个城市的等高线…...
