mybatis底层源码
一、运行原理

二、配置文件的解析以及创建SqlSessionFactory
首先通过配置文件的文件流创建SqlSessionFactoryBuilder对象

调用build方法,传入文件流

之后通过解析器解析xml配置文件

通过XPathParse解析configuration节点,获取根节点,之后再parseConfiguration()方法中根据根节点解析根节点中的每一个节点


之后来到settingsElement()方法中

environmentsElement(root.evalNode("environments"))获取数据源配置被放到了Configuration里面

解析mappers.xml配置文件

两种方式
我们看看配置文件里面mappers标签是怎么配置的,官方给出了四种配置方式:
1、Mapper.xml文件的相对路径引用(解析XML获取SQL)
2、Mapper.xml文件的绝对路径引用(解析XML获取SQL)
3、Mapper.java类文件的完全限定类名(解析注解获取SQL)
4、Mapper.java类文件所在的包路径(解析注解获取SQL)

既然配置有4种配置方法,那对应的解析的时候也有4种解析方法:
XMLConfigBuilder.mapperElement

XMLMapperBuilder.parse()获取mapper配置节点

解析mapper文件中的节点

之后调用XbuildStatementFromContext()方法,对所有的crud配置节点,进行解析

循环解析所有crud节点

解析并获取所有crud节点的属性

最后将所有的属性值加入到一个MappedStatement中,封装成MappedStatement,所以一个MappedStatement表示一个crud的SQL语句详细信息

最后还是将MappedStatement添加到configuration中,到此,configuration就填充完毕,其中保存了所有的配置信息(全局配置文件及sql映射文件)

通过configuration创建DefaultSqlSessionFactory

总结:就是将所有的配置文件信息保存在configuration中,通过configuration对象创建SqlSessionFactory
三、SqlSession对象的创建
通过SqlSessionFactory的openSession获取sqlSession

首先通过configuration.getDefaultExecutorType()获取执行器类型,默认为SIMPLE

之后又来到openSessionFromDataSource()方法

创建了一个Executor对象,来到newExecutor()方法

Executor是一个接口,用来执行crud的

是否配置了二级缓存,如果配置了使用CachingExecutor对Executor包装,实际执行crud还是Executor

包装后的Executor在查询之前会有缓存操作,Executor创建完毕后

会调用连接器链对executor进行一个拼装

循环所有的拦截器重新包装Executor,并返回

将创建好的Executor对象传入DefaultSqlSession中,DefaultSqlSession是SQLSession的实现类,
可以看出DefaultSqlSession中也包含了全局配置文件configuration的数据,最终执行crud还是Executor
总结:创建Executor对象及DefaultSqlSession对象,注意如果有二级缓存会包装Executor,其中还会使用拦截器链包装Executor
四、获取Mapper的代理对象
通过getMapper获取mapper

最终调用configuration的getMapper方法

又调用mapperRegistry的getMapper方法

mapperRegistry中保存了每一个mapper对应的MapperProxyFactory

根据接口类型获取mapperProxyFactory,通过mapperProxyFactory创建代理对象

首先创建一个mapperProxy对象,在调用newInstance方法

MapperProxy实现InvocationHandler接口,这个是JDK做动态代理需要传入的对象

之后就是通过JDK代理创建代理对象并返回,代理对象中包含了sqlSession,可以用来执行crud
总结:mapperProxyFactory在configuration初始化完毕后,一个mapper就绑定一个mapperProxyFactory,
通过mapperProxyFactory创建mapperProxy代理对象,代理对象中保存sqlSession对象,sqlSession中包含类Executor对象,用来执行crud
五、代理对象执行增删改查
调用代理的目标方法时,会先执行invoke()方法

先判断执行的方法是否是Object中的方法,否则就将方法包装为一个MapperMethod,最后执行其execute方法,传入sqlSession及方法参数

判断sql语句的类型,我这里是查询

我这里返回对象进入else流程,convertArgsToSqlCommandParam在解析参数,单个参数直接返回,多个参数返回一个map,之后调用SqlSession的selectOne方法

调用selectList查询多个方法

从configuration中通过方法id获取MappedStatement(就是configuration初始化时用来执行crud的),之后调用executor的query方法,
wrapCollection(parameter)是根据参数将其包装为一个map,map中存放数据

现获取绑定的sql

BoundSql中封装了所有的sql信息,包括sql语句,参数,参数映射关系,之后就是创建二级缓存中保存的key,之后就调用query方法

如果配置二级缓存先获取缓存,之后调用query方法,就是SimpleExecutor的query方法

先从一级缓存中查询获取,这就印证了mybatis先查询二级缓存,在查询一级缓存,如果一级缓存中也没有就执行queryFromDatabase方法

调用doQuery()查询数据,查询出数据后又加入到本地缓存中

首先声明一个Statement对象,原生JDBC对象,在获取configuration,在通过newStatementHandler创建StatementHandler对象,StatementHandler可以创建出Statement对象

首先创建一个 RoutingStatementHandler

根据配置创建不同的Statement,默认PREPARED,所以创建出一个PreparedStatementHandler,保存在RoutingStatementHandler中,
之后又将statementHandler包装在拦截器链中,之后调用prepareStatement(handler, ms.getStatementLog())方法创建Statement

在prepareStatement中有对参数进行预编译

调用parameterHandler进行参数预编译设置参数,创建PreparedStatementHandler对象时创建parameterHandler及resultSetHandler,在创建这两个对象时,
又将其包装到拦截器链中,至此mybatis的四大对象(Executor,StatementHandler,parameterHandler,resultSetHandler)就全部创建完毕,调用setParameters设置参数

调用TypeHandler给sql语句预编译设置参数,参数设置完毕就调用handler.query(stmt, resultHandler)执行查询

通过resultSetHandler处理结果

最后通过typeHandler.getResult(rs, column)返回结果
总结:先通过代理mapper对象,实际执行crud是使用sqlSession,sqlSession又是使用executor执行的,executor在执行crud时,
会创建StatementHandler,StatementHandler就是用来处理(预编译,设置参数等)sql语句,
StatementHandler创建时创建了parameterHandler及resultSetHandler,
parameterHandler设置参数等等工作,并且执行sql语句,
resultSetHandler是用来处理查询后的结果,
parameterHandler及resultSetHandler执行时都会有一个TypeHandler做设置参数及获取结果映射为javaBean,TypeHandler底层是使用JDBC操作的
六、运行流程总结
根据配置文件(全局文件及sql映射文件)初始化出Configuration
创建DefaultSqlSession对象,其中包括Configuration及Executor(根据全局配置文件中的defaultExecutorType进行初始化)
DefaultSqlSession或Mapper接口对应的MapperProxy,MapperProxy包含DefaultSqlSession
执行增删改查方法,代理对象调用DefaultSqlSession(Executor)的CRUD,创建一个Statement对象,同时创建StatementHandler,创建StatementHandler同时也会创建出parameterHandler及resultSetHandler,调用StatementHandler(parameterHandler)的预编译参数及设置参数值,在调用StatementHandler的CRUD方法,使用resultSetHandler封装结果
四大对象每个创建时都有一个拦截器链的步骤,这一步在mybatis的插件中有用。
mybatis底层源码的更多相关文章
- mybatis底层源码分析之--配置文件读取和解析
现在企业级开发中ssm是很常见的技术标配,mybatis比hibernate轻量了很多,而且学习成本相对较低,简单易上手. 那么,问题来了,简单好用的mybatis底层到底是如何实现的呢?都使用了什么 ...
- Mybatis底层源码分析
MyBatis 流程图 Configuration.xml 该配置文件是 MyBatis 的全局配置文件,在这个文件中可以配置诸多项目.常用的内容是别名设置,拦截器设置等. Properties(属性 ...
- Mybatis底层源码执行流程
1.通过类加载器,加载了config.xml文件 2.通过SqlSessionFactoryBuilder.build(resource)这个方法进行了config.xml的解析,解析为Configu ...
- 从底层源码浅析Mybatis的SqlSessionFactory初始化过程
目录 搭建源码环境 POM依赖 测试SQL Mybatis全局配置文件 UserMapper接口 UserMapper配置 User实体 Main方法 快速进入Debug跟踪 源码分析准备 源码分析 ...
- 【狂神说】JAVA Mybatis 笔记+源码
简介 自学的[狂神JAVA]MyBatis GitHub源码: https://github.com/Donkequan/Mybatis-Study 分享自写源码和笔记 配置用的 jdk13.0.2 ...
- 读源码【读mybatis的源码的思路】
✿ 需要掌握的编译器知识 ★ 编译器为eclipse为例子 调试准备工作(步骤:Window -> Show View ->...): □ 打开调试断点Breakpoint: □ 打开变量 ...
- Android开发之漫漫长途 Ⅵ——图解Android事件分发机制(深入底层源码)
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- 为什么很多类甚者底层源码要implements Serializable ?
为什么很多类甚者底层源码要implements Serializable ? 在碰到异常类RuntimeException时,发现Throwable实现了 Serializable,还有我们平进的ja ...
- List-LinkedList、set集合基础增强底层源码分析
List-LinkedList 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 继上一章继续讲解,上章内容: List-ArreyLlist集合基础增强底层源码分析:https:// ...
- List-ArrayList集合基础增强底层源码分析
List集合基础增强底层源码分析 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 集合分为三个系列,分别为:List.set.map List系列 特点:元素有序可重复 有序指的是元素的 ...
随机推荐
- Huawei LiteOS基于Cortex-M4 GD32F4平台移植
1.Huawei LiteOS简介 Huawei LiteOS源码获取: https://github.com/LiteOS/LiteOS, https://gitee.com/LiteOS/Lite ...
- redis 执行性能检测指令报错:-bash: redis-benchmark: command not found
最近在看redis相关的内容,redis有自带检测性能的命令: -bash: redis-benchmark: command not found 碰到的所有资料中均提示不能在redis客户端中执行, ...
- 离散最大似然法与 OI
若总体属于离散型,其分布律在参数 \(\theta\) 作用下 \(P\{X=x\}=p(x;\theta),\Theta=\{\theta\}\) 的形式已知,设 \(X_1,X_2,\dots,x ...
- 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-14- iframe操作-下篇(详细教程)
1.简介 通过前边两篇的学习,想必大家已经对iframe有了一定的认识和了解,是不是感觉和Python语言中的差不了多少,大同小异,最多就是不同开发语言的一些语法差异.今天这一篇主要是对iframe做 ...
- Halcon学习教程(一) 之提取十字线中心 图像分割
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/17266405.html 废话不多说,因为毕业后工作原因比较忙,好久没更新博客了,直接上图... ...
- QT5笔记:27. MDI应用程序设计
MDI:Multiple Document Interface 多窗口文档界面 例子: MainWindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H # ...
- 给Typecho加上心知天气-网页天气插件
给你的博客添加个知心天气的天气预报,代码看下面 <!-- 知心天气--> <div id="tp-weather-widget" class="navb ...
- 事务中无法切换数据源?DataSourceSwitchInvoker:轻松实现多数据源切换执行工具类
背景: 在有标注为@Transactional的类或公共方法中(传播特性,如:NOT_SUPPORTED.SUPPORTS.REQUIRED[默认值].REQUIRES_NEW)执行数据源切换可能不成 ...
- Linux - vi & vim 编辑器
vim 具有程序编辑的能力,可以主动的以字体颜色辨别语法的正确性,方便程序设计. vim 是从vi发展出来的一个文本编辑器.代码补全.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用. 使 ...
- hbase - [04] java访问hbase
需要导入jar包 $HBASE_HOME/lib下的所有jar包 $HADOOP_HOME/share/hadoop/common的所有jar包 package com.harley.hbase.te ...