mybatis-spring @MapperScan走读分析
接上一篇文章:https://blog.csdn.net/qq_26437925/article/details/145100531, 本文注解分析mybatis-spring中的@MapperScan注解,则将容易许多。
目录
- @MapperScan注解定义
- ConfigurationClassPostProcessor扫描注册beanDefinition
- org.mybatis.spring.mapper.MapperFactoryBean
- org.apache.ibatis.binding.MapperProxy
- org.apache.ibatis.executor.SimpleExecutor#doUpdate
- 总结
@MapperScan注解定义
@MapperScan注解加入了@Import(MapperScannerRegistrar.class), 所以可以知晓
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {/*** Alias for the {@link #basePackages()} attribute. Allows for more concise* annotation declarations e.g.:* {@code @EnableMyBatisMapperScanner("org.my.pkg")} instead of {@code* @EnableMyBatisMapperScanner(basePackages= "org.my.pkg"})}.*/String[] value() default {};/*** Base packages to scan for MyBatis interfaces. Note that only interfaces* with at least one method will be registered; concrete classes will be* ignored.*/String[] basePackages() default {};/*** Type-safe alternative to {@link #basePackages()} for specifying the packages* to scan for annotated components. The package of each class specified will be scanned.* <p>Consider creating a special no-op marker class or interface in each package* that serves no purpose other than being referenced by this attribute.*/Class<?>[] basePackageClasses() default {};/*** The {@link BeanNameGenerator} class to be used for naming detected components* within the Spring container.*/Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;/*** This property specifies the annotation that the scanner will search for.* <p>* The scanner will register all interfaces in the base package that also have* the specified annotation.* <p>* Note this can be combined with markerInterface.*/Class<? extends Annotation> annotationClass() default Annotation.class;/*** This property specifies the parent that the scanner will search for.* <p>* The scanner will register all interfaces in the base package that also have* the specified interface class as a parent.* <p>* Note this can be combined with annotationClass.*/Class<?> markerInterface() default Class.class;/*** Specifies which {@code SqlSessionTemplate} to use in the case that there is* more than one in the spring context. Usually this is only needed when you* have more than one datasource.*/String sqlSessionTemplateRef() default "";/*** Specifies which {@code SqlSessionFactory} to use in the case that there is* more than one in the spring context. Usually this is only needed when you* have more than one datasource.*/String sqlSessionFactoryRef() default "";/*** Specifies a custom MapperFactoryBean to return a mybatis proxy as spring bean.**/Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;}
ConfigurationClassPostProcessor扫描注册beanDefinition
mybatis-spring中自定义了org.mybatis.spring.annotation.MapperScannerRegistrar
实现了ImportBeanDefinitionRegistrar
接口,所以能被处理
mybatis-spring也实现了自己的Scanner能够扫描出所有的@Mapper的interface, 然后定义出BeanDefinition
继续debug可以看到对BeanDefinisiton 会设置BeanClass为FactoryBean类
即自定义的org.mybatis.spring.mapper.MapperFactoryBean
org.mybatis.spring.mapper.MapperFactoryBean
仍然是重点关注getObject方法
@Override
public T getObject() throws Exception {return getSqlSession().getMapper(this.mapperInterface);
}
数据库操作也封装为SqlSession接口,有多个实现类可选择
最后也会发现是java 动态代理
org.apache.ibatis.binding.MapperProxy
代理的具体实现则在mybatis依赖的MapperProxy
类中
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (Object.class.equals(method.getDeclaringClass())) {return method.invoke(this, args);} else if (isDefaultMethod(method)) {return invokeDefaultMethod(proxy, method, args);}} catch (Throwable t) {throw ExceptionUtil.unwrapThrowable(t);}final MapperMethod mapperMethod = cachedMapperMethod(method);return mapperMethod.execute(sqlSession, args);
}
sql执行
public Object execute(SqlSession sqlSession, Object[] args) {Object result;switch (command.getType()) {case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:if (method.returnsVoid() && method.hasResultHandler()) {executeWithResultHandler(sqlSession, args);result = null;} else if (method.returnsMany()) {result = executeForMany(sqlSession, args);} else if (method.returnsMap()) {result = executeForMap(sqlSession, args);} else if (method.returnsCursor()) {result = executeForCursor(sqlSession, args);} else {Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);}break;case FLUSH:result = sqlSession.flushStatements();break;default:throw new BindingException("Unknown execution method for: " + command.getName());}if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");}return result;
}
org.apache.ibatis.executor.SimpleExecutor#doUpdate
继续深入找一个简单的sql执行实现类,可以看到类似jdbc的处理流程
总结
最后还是回到了上一篇博文:https://blog.csdn.net/qq_26437925/article/details/145100531。只不过mybatis-spring要丰富一些,原理仍然是动态代理,BeanFactoryPostProcessor ,FactoryBean,BeanPostProcessor这些基础知识。
相关文章:

mybatis-spring @MapperScan走读分析
接上一篇文章:https://blog.csdn.net/qq_26437925/article/details/145100531, 本文注解分析mybatis-spring中的MapperScan注解,则将容易许多。 目录 MapperScan注解定义ConfigurationClassPostProcessor扫描注册beanDefinitionorg.mybatis.s…...

Mysql--架构篇--体系结构(连接层,SQL层,存储引擎层,文件存储层)
MySQL是一种广泛使用的关系型数据库管理系统(RDBMS),其体系结构设计旨在提供高效的数据存储、查询处理和事务管理。MySQL的体系结构可以分为多个层次,每个层次负责不同的功能模块。 MySQL的体系结构主要由以下几个部分组成&#…...

【0x005B】HCI_Write_Default_Erroneous_Data_Reporting命令详解
目录 一、命令概述 二、命令格式及参数 2.1. HCI_Write_Default_Erroneous_Data_Reporting命令格式 2.2. Erroneous_Data_Reporting 三、生成事件及参数 3.1. HCI_Command_Complete事件 3.2. 状态码(Status) 四、命令执行流程 4.1. 命令发起阶段(主机端) 4.2. 命…...
基于 Python 的学生成绩管理系统设计与实现
标题:基于 Python 的学生成绩管理系统设计与实现 内容:1.摘要 摘要:本文介绍了一个基于 Python 的学生成绩管理系统的设计与实现。该系统旨在提高学生成绩管理的效率和准确性,方便教师和学生进行成绩查询和分析。本文详细描述了系统的设计思路、功能模块…...

【Apache Doris】周FAQ集锦:第 29 期
引言 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目! 在这个栏目中,每周将筛选社区反馈的热门问题和话题,重点回答并进行深入探讨。旨在为广大用户和开发者分享有关 Apache Doris 的常见问题。 通过这个每周 FAQ 栏目,希望帮助社…...

【C】初阶数据结构3 -- 单链表
之前在顺序表那一篇文章中,提到顺序表具有的缺点,比如头插,头删时间复杂度为O(n),realloc增容有消耗等。而在链表中,这些问题将得到解决。所以在这一篇文章里,我们将会讲解链表的定义与性质,以及…...

Autodl安装tensorflow2.10.0记录
首先租用新实例(我选的是3080*2卡),由于基础镜像中没有2.10.0版本,选miniconda3的基础环境 创建虚拟环境:conda create --name xxx python3.8(环境名)激活虚拟环境:conda activate x…...

【Rust】常见集合
目录 思维导图 一、Rust常用集合 1. Rust标准库中的集合概述 2. 常用集合类型 2.1 向量(Vector) 2.2 字符串(String) 2.3 哈希映射(Hash Map) 二、向量(Vec) 1. 向量的概述…...

SpiderFlow平台v0.5.0之引入selenium插件
引入selenium插件 首先到码云下载插件点击下载编辑到本地并导入到工作空间或安装到maven库在spider-flow/spider-flow-web/pom.xml中引入插件 <!-- 引入selenium插件 --> <dependency><groupId>org.spiderflow</groupId><artifactId>spider-…...
git push命令
git push 常用命令 1. 拉取远程仓库最新数据 使用 git fetch git fetch作用: 获取远程仓库的最新数据(包括分支、标签等),但不会修改本地工作目录。 结果: 仅更新远程分支(如 origin/main)的…...

洛谷P1161
开灯 - 洛谷 代码区: #include<stdio.h> int ans[2000005]{1}; //1为关 int main(){int n;scanf("%d",&n);double arry[n][2];//此处最好用双精度浮点数,单精度浮点数的精确度够高对于此题来说,第一次没全对就是因为精度…...
Python脚本自动发送电子邮件
要编写一个Python脚本来自动发送电子邮件,你可以使用smtplib库来处理SMTP协议,以及email库来构建邮件内容。 安装必要的库 通常情况下,smtplib和email库是Python标准库的一部分,因此不需要额外安装。如果你使用的是较旧的Python版…...

vscode的安装与使用
下载 地址:https://code.visualstudio.com/ 安装 修改安装路径(不要有中文) 点击下一步,创建桌面快捷方式,等待安装 安装中文插件 可以根据自己的需要安装python和Jupyter插件...

sparkRDD教程之必会的题目
1.前期准备 (1)看看上一期的博客,最好跟着上一期的博客把sparkRDD的基本命令给熟练掌握后,再来做这篇文章的任务。 上一期的博客:sparkRDD教程之基本命令-CSDN博客 (2)新建文件task6.scala …...

Unity 2d描边基于SpriteRender,高性能的描边解决方案
目标 以Unity默认渲染管线为例,打造不需要图片内边距,描边平滑,高性能的描边解决方案 前言 在2d游戏中经常需要给2d对象添加描边,来突出强调2d对象 当你去网上查找2d描边shader,移植到项目里面,大概率会…...

信凯科技业绩波动明显:毛利率远弱行业,资产负债率偏高
《港湾商业观察》施子夫 1月8日,深交所官网显示,浙江信凯科技集团股份有限公司(以下简称“信凯科技”)主板IPO提交注册。 自2022年递交上市申请,信凯科技的IPO之路已走过两年光景,尽管提交注册࿰…...
js基础---var与let的区别以及const的使用
js基础—var与let的区别以及const的使用 var与let的区别 在较旧的JavaScript,使用关键字var来声明变量,而不是let。var现在开发中一般不再使用它,只是我们可能再老版程序中看到它。let的出现为了解决var的一些问题。 var 声明存在以下三种问…...

用css和html制作太极图
目录 css相关参数介绍 边距 边框 伪元素选择器 太极图案例实现、 代码 效果 css相关参数介绍 边距 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>*{margin: 0;padding: 0;}div{width: …...

OJ12:160. 相交链表
目录 题目思路分析代码展示 题目 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 示例 1: 输入:intersectVal 8, listA [4,1,8,4,5], listB [5,…...
软件工程和项目管理领域 - CMMI 极简理解
CMMI 概述 CMMI 全称为 Capability Maturity Model Integration,即能力成熟度模型集成 CMMI 是由美国卡内基梅隆大学软件工程研究所(SEI)开发的一套综合性管理模型 CMMI 是一种用于评估和改进组织在软件开发和维护方面过程能力的国际标准 …...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...

用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...