搞懂MyBatis与Spring Boot整合:两大核心类自动装配原理与排错
搞懂 MyBatis 和 Spring Boot 的整合原理其实只要抓住两个类MybatisAutoConfiguration和AutoConfiguredMapperScannerRegistrar。我们常用 Spring Boot 的人都知道加一个mybatis-spring-boot-starter就能自动装配 SqlSessionFactory、Mapper 扫描这些能力但真正遇到问题的时候比如 Mapper 没被扫描、多数据源下自动配置失效、加了 MapperScan 还是报 no bean如果不把底层这两个类弄明白排查基本靠猜。我之前接手过一个老项目原来用的是手写 XML 配置和 Spring 手动注册 SqlSessionFactory 的方式后来要迁到 Spring Boot 自动装配过程里踩了不少坑。今天就把我梳理过的原理、源码分析和排查经验一次性写出来。1. 首先理解 Spring Boot 是怎么“自动”把 MyBatis 装配起来的1.1 自动配置的真正入口在 starter 的 jar 包里mybatis-spring-boot-starter表面上只负责引入依赖真正干活的其实是mybatis-spring-boot-autoconfigure这个模块。它内部通过 Spring Boot 的自动配置加载机制把MybatisAutoConfiguration这个配置类注册到容器候选列表里。Spring Boot 的自动配置入口老版本靠META-INF/spring.factories文件里的EnableAutoConfiguration配置项在新版本里则是META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件。这个机制可以简单理解成Spring Boot 启动时内部会专门找所有AutoConfiguration.imports文件把所有xxxAutoConfiguration类收集起来接着做条件判断满足条件的才真正保留。所以MybatisAutoConfiguration不是被某个Configuration显式引入的而是这个“自动配置收集器”找到的。它会被AutoConfigurationImportSelector统一加载执行顺序在常规用户配置类之后这样用户如果想覆盖默认配置有优先权。1.2 自动配置类上的条件注解决定了它什么时候生效MybatisAutoConfiguration是一个配置类但并不是无脑生效的它头上挂了一堆条件注解。核心几个是ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})类路径里必须有 MyBatis 和 mybatis-spring 的核心类否则自动配置直接跳过。ConditionalOnSingleCandidate(DataSource.class)容器里只能有一个 DataSource 候选如果配了多数据源这个条件不满足自动配置就失效。ConditionalOnMissingBean容器里没有用户自定义的同类型 Bean 时才自动创建。这个设计思路很典型Spring Boot 默认帮你做事情但你一旦自己定义了关键 Bean它的自动配置就主动退让避免冲突。这也是为什么很多老开发者习惯手动写一个SqlSessionFactory类型的Bean方法后自动配置就不再重复创建了。1.3 配置属性绑定到了哪里MybatisAutoConfiguration上还有EnableConfigurationProperties(MybatisProperties.class)把application.yml里以mybatis开头的配置项绑定到MybatisProperties对象。常见的有mybatis: mapper-locations: classpath:mapper/**/*.xml type-aliases-package: com.example.domain configuration: map-underscore-to-camel-case: true cache-enabled: false这些配置最终会在创建SqlSessionFactory的时候被读进去只要理解了属性绑定逻辑后面看它怎么构建工厂就容易多了。2. MybatisAutoConfiguration 内部拆解它到底创建了哪些核心 Bean2.1 宏观结构一个配置类内部还藏了一个 RegistrarMybatisAutoConfiguration本身是一个Configuration类里面定义了多个Bean。但它的内部还嵌套了一个AutoConfiguredMapperScannerRegistrar这个内部类实现了ImportBeanDefinitionRegistrar接口。我先说结论MybatisAutoConfiguration负责把“数据库访问基础设施”搭好比如 SqlSessionFactory、SqlSessionTemplateAutoConfiguredMapperScannerRegistrar负责把 Mapper 接口变成能被注入的 Bean。两者职责不同但是相互配合。2.2 SQL 会话工厂是如何创建的关键Bean方法一般是这样的逻辑Bean ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factory new SqlSessionFactoryBean(); factory.setDataSource(dataSource); // 设置 mapperLocations // 设置 typeAliases // 设置 configurationProperties return factory.getObject(); }这里有个容易被忽略的点真正实例化 SqlSessionFactory 的不是一个简单的 new而是通过SqlSessionFactoryBean这个实现了FactoryBeanSqlSessionFactory的类。为什么要绕这么一层因为 SqlSessionFactory 本身的配置项特别多像Configuration、mapperLocations、typeAliasesPackage、plugins如果全用构造器拼调用方代码会非常冗长且不可维护。SqlSessionFactoryBean更像一个“工厂和配置的合体”Spring 的 IoC 容器会先创建它再调用其getObject()方法得到最终的 SqlSessionFactory同时它还能校验 XMl 映射文件是否存在。看完源码你就知道MybatisAutoConfiguration做了不少额外处理比如如果MybatisProperties里指定了configuration就用它作为 MyBatis 的 Configuration。如果指定了mapperLocations就把这些 XML 资源注册到 Configuration 里。会把容器里已有的InterceptorMyBatis 拦截器注入到SqlSessionFactoryBean的 plugins 里这就是为什么你即使不在配置里写拦截器只要声明了一个Bean InterceptorMyBatis 也会自动使用它。2.3 SqlSessionTemplate 的职责和为什么有它SqlSessionTemplate是 MyBatis 的核心入口之一它实现了SqlSession接口但你很少直接看到它因为 Mapper 代理在底层调用的是它。MybatisAutoConfiguration也会创建一个SqlSessionTemplate类型的 Bean依赖前面生成的SqlSessionFactory。可以把 SqlSessionTemplate 理解成“MyBatis 和 Spring 之间的适配器”平时我们自己写 MyBatis 代码要手动开SqlSession、提交、关闭而SqlSessionTemplate负责把这些和 Spring 的事务管理结合起来。当方法上标注了Transactional真正让 SqlSession 提交或回滚的是 Spring 事务而不是某一个 Mapper 方法内部临时开的 Session。所以如果你在自己的项目里手动覆盖了SqlSessionFactory一定要同步提供一个SqlSessionTemplate否则依赖SqlSessionTemplate注入的地方会直接报“没有可用 Bean”。这点在后面的排错部分我会再提到。3. AutoConfiguredMapperScannerRegistrar 逐层剖析Mapper 到底是怎么被发现的3.1 没有 MapperScan它是怎么找到 Mapper 的很多人会有个疑问我从没写MapperScan只在接口上加了Mapper注解为什么 Spring Boot 就能识别并注入这些 Mapper答案就是AutoConfiguredMapperScannerRegistrar。这个内部类同样是ImportBeanDefinitionRegistrar它会在容器启动阶段向BeanDefinitionRegistry注册一个MapperScannerConfigurer的 BeanDefinition。MapperScannerConfigurer是一个BeanDefinitionRegistryPostProcessor在容器实例化 Bean 之前进行扫描和注册。它默认做的核心事情是从AutoConfigurationPackages中拿到自动配置的根包名。注册MapperScannerConfigurer的时候把basePackage设为这个根包。把annotationClass设为Mapper.class。交给ClassPathMapperScanner扫包把所有接口扫描出来并注册为 MapperFactoryBean。这里最关键的是第 1 步。Spring Boot 在自动配置时会把主启动类所在的包记录到AutoConfigurationPackages里相当于一个“自动配置包”。MybatisAutoConfiguration内部正是基于这个包作为默认扫描范围所以 Mapper 接口放在启动类所在包或者子包里才能被默认扫到。这也能解释一个高频报错如果 Mapper 接口放在和启动类完全无关的包路径下即使加了Mapper注解它也不会被自动扫描因为默认扫描的根包不对。3.2 registerBeanDefinitions 里的实际逻辑AutoConfiguredMapperScannerRegistrar的核心逻辑简化后是这个样子Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 没有自动配置包就直接返回避免报错 if (!AutoConfigurationPackages.has(registry)) { return; } // 拿到自动配置包的包名列表 ListString packages AutoConfigurationPackages.get(registry); // 创建 MapperScannerConfigurer 的 Bean 定义 BeanDefinitionBuilder builder BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); builder.addPropertyValue(basePackage, StringUtils.collectionToCommaDelimitedString(packages)); builder.addPropertyValue(annotationClass, Mapper.class); // 注册到容器 registry.registerBeanDefinition( AutoConfiguredMapperScannerRegistrar.class.getName(), builder.getBeanDefinition()); }注意它不是直接调ClassPathMapperScanner.scan()而是注册一个MapperScannerConfigurer这符合 Spring Boot 的延迟初始化思路把扫描行为交给后置处理器等到对应的阶段再执行。这个设计使得用户可以仍然通过自定义MapperScannerConfigurer覆盖默认行为。3.3 和 MapperScan 的差异如果用户写了MapperScan(basePackages com.example.mapper)它会引入另外一套机制效果是注册一个MapperScannerConfigurer并把扫描包设置为注解里指定的包。这两套机制最大的差异是MapperScan让你显式指定扫描包灵活但容易因为包路径写错而扫不到。AutoConfiguredMapperScannerRegistrar走默认包路径只扫Mapper标注的接口省心但灵活性不足。它们之间还有一个优先级关系AutoConfiguredMapperScannerRegistrar上带有ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})相关的条件也就是说容器里一旦有用户通过MapperScan或自定义方式注册了MapperScannerConfigurer自动配置的扫描逻辑就不再重复执行。这避免了重复注册 Mapper Bean。4. 根据原理反推实际排查常见问题与解决办法4.1 报错“没有 Mapper Bean”时不要只看注解我在实际项目里最常遇见的错误是Description: Field userMapper in com.example.service.UserService required a bean of type com.example.mapper.UserMapper that could not be found.很多人第一反应是检查Mapper有没有加、MapperScan有没有写。但漏了一个点AutoConfiguredMapperScannerRegistrar的默认扫包路径是启动类所在包。如果项目结构是下面这样com.example.app.MainApplication com.example.data.mapper.UserMapper那么即使UserMapper加了Mapper默认扫描也扫不到因为com.example.data不在com.example.app的包树下。排查步骤我一般这样走看启动类所在位置和 Mapper 接口包路径的关系。看有没有多个MapperScan互相覆盖。看是否存在多个MapperScannerConfigurer导致后注册的覆盖前面注册的。打开debugtrue看自动配置报告确认MybatisAutoConfiguration是否生效。启动时加debugtrue或--debug控制台会打印 “Positive matches” 和 “Negative matches”直接搜 MybatisAutoConfiguration 就能看到它有没有被排除以及被排除的原因。这一步往往比瞎找注解有用得多。4.2 多数据源时自动配置为什么静默失效这是很多人在从单数据源切到多数据源后才会遇到的坑。MybatisAutoConfiguration上的核心条件之一是ConditionalOnSingleCandidate(DataSource.class)。当你配置了多个DataSource并且它们是同一类型时Spring 容器里不再有“唯一候选”的 DataSourceMybatisAutoConfiguration就会自动跳过。跳过之后SqlSessionFactory和SqlSessionTemplate都不会自动创建如果你也没手动配置项目启动可能不会立刻报错但只要有一个地方注入SqlSessionFactory或者某个 Mapper就会报找不到 Bean。解决办法也很典型自己写一个配置类分别给每个数据源创建独立的SqlSessionFactory、SqlSessionTemplate、DataSourceTransactionManager再通过MapperScan指定不同的包扫描到不同的 SqlSessionTemplate。比如Configuration public class MultiDataSourceConfig { Bean public SqlSessionFactory primarySqlSessionFactory( Qualifier(primaryDataSource) DataSource dataSource) throws Exception { SqlSessionFactoryBean factory new SqlSessionFactoryBean(); factory.setDataSource(dataSource); return factory.getObject(); } Bean public SqlSessionTemplate primarySqlSessionTemplate( Qualifier(primarySqlSessionFactory) SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }同时两个 Mapper 扫描要分别指定sqlSessionTemplateRef否则 Mapper 不知道用哪个会话。4.3 手动覆盖 SqlSessionFactory 容易踩的连锁问题还有一类问题是“我自定义了 SqlSessionFactory结果 mybatis 配置全失效了”。原因通常在于MybatisProperties里的属性只会在MybatisAutoConfiguration创建 Bean 时读取一遍。一旦你自己写了Bean SqlSessionFactory自动配置不再生成你的手动 Bean 又没读取原来的配置项比如 mapper-locations自然 XML 映射就加载不到。解决方式有两个方向在自己的SqlSessionFactoryBean里手动读取MybatisProperties把需要的配置项逐个设置进去。更推荐的做法不要在启动类所在包额外声明SqlSessionFactory而是用MybatisAutoConfiguration的默认创建只通过application.yml调整配置。如果确实需要拦截器或者自定义对象工厂可以声明对应的Bean让自动配置感知到。5. 针对这套机制的个人实操体会最后分享两个我自己排查时觉得特别有用的细节。第一个是遇到 Mapper 相关的诡异问题时不要急着反编译或改代码先在启动参数加--debug看自动配置的匹配报告。它会把MybatisAutoConfiguration是被哪个条件挡住的直接打出来指向性非常明确。很多时候问题根本不是 Mapper 扫描而是DataSource不唯一连带着整个 MyBatis 自动配置被跳过了。第二个是如果你在项目里用到了多个 MyBatis 插件比如分页插件、逻辑删除插件最好统一通过Bean方式注册成Interceptor而不是在mybatis.configuration里手工写拦截器类名。原因很简单自动配置创建SqlSessionFactory时会把容器里的Interceptor收集起来统一设置如果你手工写字符串方式一旦类名写错或者类路径调整错误会被延迟到真正执行 SQL 时才发现排错成本远高于启动时报错。这也是我后来更倾向于“让自动配置多干活我少干活”的原因。Spring Boot 这套设计虽然把细节隐藏在自动配置里但只要你抓住MybatisAutoConfiguration和AutoConfiguredMapperScannerRegistrar这两个核心理解它们“搭基础设施 扫 Mapper 接口”的分工很多问题就都能从原理层面找到答案而不是停留在盲试不同的注解组合。

相关新闻

Vue项目中Tinymce自定义本地视频上传完整指南

Vue项目中Tinymce自定义本地视频上传完整指南

说到富文本编辑器,Vue项目里在地选择Tinymce的人真不少,我也是被它的扩展性吸引的。但前阵子做某知识库后台,客户要求用户能直接从本地选择视频传到编辑器里,并且要在文章里正常播放。原以为Tinymce自带的媒体插件能搞定&#xff…

2026/10/15 19:17:12 阅读更多 →
Attention-transfer:轻量化模型注意力迁移实战指南

Attention-transfer:轻量化模型注意力迁移实战指南

1. 项目概述:为什么“Attention-transfer”成了轻量化网络学习里绕不开的关键词最近在几个高校实验室和工业界模型压缩团队的交流中,反复听到一个词——“Attention-transfer”。它不像知识蒸馏(Knowledge Distillation)那样被写进…

2026/10/15 19:17:12 阅读更多 →
MySQL 基础 + AI SQL 优化

MySQL 基础 + AI SQL 优化

楠风测开 测试工程师复习日记 Day15 用一套订单、支付和库存样例,把查询、关联、金额核对与事务验证串起来。 前言:SQL跑通之后,还差一次结果验收 朋友们好,我是楠风。 上一阶段聊完Linux监控,我们开始补上测试工程…

2026/10/15 19:17:12 阅读更多 →

最新新闻

云开发+短信API:零成本搭建员工生日自动提醒系统

云开发+短信API:零成本搭建员工生日自动提醒系统

每年一到员工生日这种日子,行政和HR就开始手忙脚乱。翻Excel、找手机号、挨个发祝福语,还要赶在当天发出,稍微一忙就会漏掉一两个。之前我们团队就是这么干的,直到有一次连续漏了三个同事的生日,被吐槽“公司没有人情味…

2026/10/15 20:02:24 阅读更多 →
Arcpy批量导出地图脚本:从手动出图到自动化流水线

Arcpy批量导出地图脚本:从手动出图到自动化流水线

1. 从手动一张张出图到批量流水线:这个脚本到底解决什么问题如果你做过GIS制图,大概率经历过这样的场景:手头有一份行政区划图层,领导要求按每个乡镇出一张专题图,一共几十上百个。打开ArcMap或ArcGIS Pro,…

2026/10/15 20:02:24 阅读更多 →
离散数学笔记高效整理法:五大板块与复习避坑指南

离散数学笔记高效整理法:五大板块与复习避坑指南

简介:这是一份系统梳理离散数学核心知识点的PDF笔记,围绕数理逻辑、集合论、数论、计数原理、概率论、关系论、代数系统与图论八大板块展开,适合高校本科生、考研复习者及程序员巩固理论基础。笔记从命题逻辑的永真式与范式讲起,依…

2026/10/15 20:02:24 阅读更多 →
python代码学习1

python代码学习1

摘要:f的用法、print中可用的操作、for、列表、ASCII编码一、f的用法:在输出里调整格式1.直接嵌入变量/表达式a 18 print(f"今年{a}岁") # 今年18岁2.保留有效数字pi 3.1415926 print(f"{pi:.2f}") # 3.14 print(f"{pi…

2026/10/15 20:02:24 阅读更多 →
IIS 6.0离线安装包:含全部DLL与注册表修复的SP2兼容部署方案

IIS 6.0离线安装包:含全部DLL与注册表修复的SP2兼容部署方案

简介:本资源为IIS 6.0完整安装支持包,面向Windows Server 2003系统管理员、传统Web运维人员及遗留系统维护开发者,专为解决IIS 6.0原生安装因缺失关键DLL导致失败或功能异常的典型问题。压缩包内含263个文件,涵盖19个核心DLL&…

2026/10/15 20:02:24 阅读更多 →
VMware复制粘贴失效?从VMware Tools到客户机隔离全排查指南

VMware复制粘贴失效?从VMware Tools到客户机隔离全排查指南

你是不是也遇到过这样的场景:虚拟机里装好了系统,想在宿主机和虚拟机之间复制一段代码、一个下载链接、一小段配置,结果CtrlC、CtrlV按了半天一点反应都没有;换成拖放文件,鼠标倒是能移过去,文件却死活拖不…

2026/10/15 20:01:22 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →