MyBatis 执行流程及源码解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: MyBatis 执行流程及源码解析

我们在日常工作中广泛使用mybatis作为数据持久层框架,但是mybatis的执行流程是怎么样的,你了解过吗。本文将从源码角度,带你分析mybatis的工作原理。

先看一个简单的例子,以Service调用Mapper接口为例:

public interface StudentMapper {
    @Select("select * from student")
    public List<Map<String,Object>> query();
}
@Service("studentService")
public class StudentServiceImpl implements StudentService {
    @Autowired
    StudentMapper studentMapper;
    @Override
    public List<Map<String, Object>> query() {
        return studentMapper.select();
    }
}

向Service中注入这个Mapper并调用时,你知道这时注入的是什么吗?

image.png

通过调试,可以知道这时实际的studentMapper是一个类型为MapperProxy的代理对象,下面将从myabtis环境初始化开始,具体分析代理对象的产生过程。(不熟悉代理对象的同学,可以查看之前专门讲java代理的文章)

一、配置SqlSessionFactoryBean 时都做了什么?

在进行spring和mybatis整合时,会用xml或者注解的方式去配置一个SqlSessionFactoryBean,本文中以注解方式为例:

@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
   SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
   sqlSessionFactoryBean.setDataSource(dataSource);
   return  sqlSessionFactoryBean;
}

看一下SqlSessionFactoryBean的继承实现关系:

image.png

先看spring中两个非常重要的接口,FactoryBean和InitializingBean。

FactoryBean:

FactoryBean是一个spring中比较特殊的Bean,通过它的getObject()方法可以返回一个对象实例。SqlSessionFactoryBean中getObject()方法的实现:

image.png

在这里用于创建并返回一个SqlSessionFactory,在 spring +mybatis 的环境下,我们使用SqlSessionFactoryBean来充当SqlSessionFactory。

InitializingBean:

InitializingBean接口中只有一个方法,afterPropertiesSet(),所有实现了接口的类,在bean的初始化之前都要调用这个方法。可以看出在上面的getObject方法中,如果SqlSessionFactory为空,会调用这个方法创建SqlSessionFactory

image.png

通过调用SqlSessionFactoryBuilder的build方法,最终返回了一个DefaultSqlSessionFactory实例,这个DefaultSqlSessionFactory中保存了一个非常重要的Configuration对象。

二、@MapperScan都做了什么?

在注解配置mybatis时,通过@MapperScan指定Mapper存放的包,就能自动为我们把接口实现成类。那么这是怎么实现的呢?

点开@MapperScan的源码,发现上面还有一行非常重要的注解:

@Import(MapperScannerRegistrar.class)

image.png

ImportBeanDefinitionRegistrar接口提供registerBeanDefinitions方法向用户暴露了BeanDefinitionRegistry,也就是说可以让用户手动创建BeanDefinition并使用该注册器注册到spring容器中。

查看MapperScannerRegistrar的方法registerBeanDefinitions中的核心代码

ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
……
scanner.doScan(StringUtils.toStringArray(basePackages));

主要是创建了一个Mapper扫描器,开启扫描。

ClassPathMapperScanner中doScan方法:

image.png

这里对生成的mapper的bean定义做了进一步处理

进入processBeanDefinitions()方法:

image.png

注意画框代码及上方的注释,先看一下从BeanDefinitionHolder获得BeanDefinition时beanClass初始的值:

image.png

等待setBeanClass执行完毕:

image.png

通过definition.setBeanClass()把原来的BeanClass的类型替换成了MapperFactoryBean类型。到这,完成了Mapper接口加载定义阶段中非常重要的一步,而这也是生成代理对象MapperProxy的关键。

三、mybatis如何生成代理对象?

看一下MapperFactoryBean的继承关系:

image.png

MapperFactoryBean继承的SqlSessionDaoSupport类实现了InitializingBean接口,那么我们还是首先找afterPropertiesSet()方法:

image.png

DaoSupport中,最终调用MapperFactoryBean中的方法:

image.png

首先通过获取sqlSession获得了非常重要的配置类Configuration,然后查看一下addMapper方法,最终调用的是MapperRegistry的addMapper方法:

image.png

红框中的代码为我们创建了Mapper 的代理工厂对象(还不是Mapper的代理对象),并把它放入了knownMappers这个Map中。

image.png

在这一步,只是简单初始化了MapperProxyFactory,把我们自己的mapper的类型传给了它,还并没有真正产生代理对象。

MapperRegistry并在之后的parse()方法中完成了xml文件的解析,每一个sql方法都被解析成了一个MappedStatement对象,并添加到了配置类Configuration对象中。

MapperFactoryBean最终返回了什么?

因为MapperFactoryBean实现了FactoryBean接口,所以我们看看getObject方法究竟返回了什么:

image.png

最终调用MapperRegistry的getMapper方法:

image.png

这里调用的了mybatis刚才生成的MapperProxyFactory,帮助我们实例化并返回了一个代理对象。MapperProxyFactory中使用newInstance方法,实例化MapperProxy,用于生成代理

image.png

至此,我们已经弄明白了文章开头的MapperProxy是如何生成的。

四、MapperProxy代理对象如何执行sql语句?

在StudentServiceImpl中的query方法中打一个断点跟踪语句,你会发现实际执行的就是代理类MapperProxy中的invoke()方法。

image.png

MapperProxy在作为代理类的同时,自身实现了InvocationHandler接口,所以invoke方法就是真正执行的代理逻辑。

image.png

在这里最终调用了MapperMethod的execute方法实际去执行了sql语句。

image.png

在该方法中,根据sql语句执行类型,调用sqlSession对应的方法执行并将结果返回给用户。至此,mybatis在spring环境下一次调用全部完成。


相关文章
|
1天前
|
监控 安全 开发工具
鸿蒙HarmonyOS应用开发 | HarmonyOS Next-从应用开发到上架全流程解析
HarmonyOS Next是华为推出的最新版本鸿蒙操作系统,强调多设备协同和分布式技术,提供丰富的开发工具和API接口。本文详细解析了从应用开发到上架的全流程,包括环境搭建、应用设计与开发、多设备适配、测试调试、应用上架及推广等环节,并介绍了鸿蒙原生应用开发者激励计划,帮助开发者更好地融入鸿蒙生态。通过DevEco Studio集成开发环境和华为提供的多种支持工具,开发者可以轻松创建并发布高质量的鸿蒙应用,享受技术和市场推广的双重支持。
113 11
|
5天前
|
域名解析 弹性计算 安全
阿里云服务器租用、注册域名、备案及域名解析完整流程参考(图文教程)
对于很多初次建站的用户来说,选购云服务器和注册应及备案和域名解析步骤必须了解的,目前轻量云服务器2核2G68元一年,2核4G4M服务器298元一年,域名注册方面,阿里云推出域名1元购买活动,新用户注册com和cn域名2年首年仅需0元,xyz和top等域名首年仅需1元。对于建站的用户来说,购买完云服务器并注册好域名之后,下一步还需要操作备案和域名绑定。本文为大家展示阿里云服务器的购买流程,域名注册、绑定以及备案的完整流程,全文以图文教程形式为大家展示具体细节及注意事项,以供新手用户参考。
|
22天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
50 12
|
2月前
|
JavaScript 前端开发 开发者
Vue执行流程及渲染解析
【10月更文挑战第2天】
112 58
|
26天前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
|
2月前
|
JavaScript 前端开发 UED
Vue执行流程及渲染解析
【10月更文挑战第5天】
|
2月前
|
存储 搜索推荐 数据库
运用LangChain赋能企业规章制度制定:深入解析Retrieval-Augmented Generation(RAG)技术如何革新内部管理文件起草流程,实现高效合规与个性化定制的完美结合——实战指南与代码示例全面呈现
【10月更文挑战第3天】构建公司规章制度时,需融合业务实际与管理理论,制定合规且促发展的规则体系。尤其在数字化转型背景下,利用LangChain框架中的RAG技术,可提升规章制定效率与质量。通过Chroma向量数据库存储规章制度文本,并使用OpenAI Embeddings处理文本向量化,将现有文档转换后插入数据库。基于此,构建RAG生成器,根据输入问题检索信息并生成规章制度草案,加快更新速度并确保内容准确,灵活应对法律与业务变化,提高管理效率。此方法结合了先进的人工智能技术,展现了未来规章制度制定的新方向。
46 3
|
2月前
|
存储 缓存 边缘计算
揭秘直播带货背后的黑科技:播放流程全解析!
大家好,我是小米,今天聊聊社区直播带货的技术细节。我们将探讨直播播放流程中的关键技术,包括 HTTP DASH 协议、POP(Point of Presence)缓存和一致性哈希算法等。通过这些技术,直播流能根据网络状况动态调整清晰度,保证流畅体验。POP 和 DC 的多层次缓存设计减少了延迟,提升了观看效果。无论是技术人员还是直播运营者,都能从中受益。希望通过本文,你能更好地理解直播背后的技术原理。
57 3
|
2月前
|
敏捷开发 数据可视化 测试技术
解析软件项目管理:以板栗看板为例,其如何有效影响并优化软件开发流程
软件项目管理是一个复杂而重要的过程,涵盖了软件产品的创建、维护和优化。其核心目标是确保软件项目能够顺利完成,同时满足预定的质量、时间和预算目标。本文将深入探讨软件项目管理的内涵及其对软件开发过程的影响,并介绍一些有效的管理工具。
|
2月前
|
JSON JavaScript API
商品详情数据接口解析返回的JSON数据(API接口整套流程)
商品详情数据接口解析返回的JSON数据是API接口使用中的一个重要环节,它涉及从发送请求到接收并处理响应的整个流程。以下是一个完整的API接口使用流程,包括如何解析返回的JSON数据:

推荐镜像

更多