当前位置: 首页 > news >正文

Spring Boot + MyBatis 报 Invalid bean definition 如何排查解决

网罗开发(小红书、快手、视频号同名)

  大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
📣 公众号“Swift社区”,每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
💬 微信端添加好友“fzhanfei”,与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。
📅 最新动态:2025 年 3 月 17 日
快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!


文章目录

    • 前言
    • 摘要
    • 为什么会发生
    • 排查步骤
    • 可运行 Demo
      • `pom.xml`
      • `application.properties`(`src/main/resources/application.properties`)
      • `schema.sql`(`src/main/resources/schema.sql`)
      • 实体类 `User.java`(`src/main/java/com/example/demo/model/User.java`)
      • Mapper 接口 `UserMapper.java`(`src/main/java/com/example/demo/mapper/UserMapper.java`)
      • 启动类 `DemoApplication.java`(`src/main/java/com/example/demo/DemoApplication.java`)
    • 运行方式
    • 其他可能的坑与补充建议
    • 总结

前言

一段非常常见又让人头大的问题:Spring Boot 项目启动时报 Invalid bean definition with name 'userMapper' ... Invalid value type for attribute 'factoryBeanObjectType': java.lang.String。你已经把网上的各种注解检查过了,最后发现把 mybatis-spring-boot-starter 升级到 3.0.3 后问题消失——这是对的。下面把问题的本质、常见根因、排查流程和彻底可运行的 Demo(可直接跑)整理成一篇易读的技术博客,方便你理解和复用。

摘要

这个错误通常不是因为写错 @Mapper 注解或 Mapper 接口方法,而是运行时类路径上的 MyBatis / MyBatis Spring Boot Starter 与当前 Spring Boot 版本不兼容,导致 Spring 在处理 MapperFactoryBean 的 factoryBeanObjectType 属性时拿到了错误的类型(字符串),从而触发校验失败。解决办法主要是:对齐依赖版本(升级/降级 mybatis starter)或移除冲突的旧版本,并用 mvn dependency:tree 检查冲突。

为什么会发生

Spring 在处理 Mapper 接口时会为每个接口注册一个 MapperFactoryBean(或者某种 FactoryBean),Spring 会读取该 FactoryBean 的元信息(factoryBeanObjectType)来做 bean 定义校验。如果类路径中某个库版本不对,或 MapperFactoryBean 的实现不同(返回了字符串而非 Class<?>),Spring 会在启动阶段判断类型不符合而抛出异常。

常见导致这种问题的根源包括:

  • mybatis-spring-boot-starter 的版本与 Spring Boot 版本不匹配(例如 starter 包里对 Spring API 的使用方式与当前 Spring 版本期望不一致)。
  • 项目中同时存在多个不同版本的 MyBatis / MyBatis-Spring / mybatis-spring-boot-starter(jar 冲突)。
  • 误把 mapper 的实现类或注解写得奇怪,导致生成的 bean 元数据异常(不常见,相对概率小)。

你遇到的场景:把 mybatis-spring-boot-starter3.0.0 改为 3.0.3(starter 内含 MyBatis 3.5.13)后问题解决,说明确实是版本兼容/bug 问题。

排查步骤

当你看到类似错误时,推荐按下面步骤排查,能快速定位问题:

  1. 查看完整异常栈,定位是哪个 Bean(userMapper)和哪个 class file。

  2. 执行 mvn dependency:tree,查找 mybatis / mybatis-spring / mybatis-spring-boot-starter 是否出现多个版本(特别是传递依赖冲突)。

    mvn dependency:tree | grep -i mybatis
    
  3. 检查 pom.xml 中是否显式或隐式引入了旧版 mybatis(通过其他 starter/库引入)。

  4. 尝试把 mybatis starter 升级到兼容版本(比如 3.0.3),或使用 Spring Boot 推荐的 starter 版本。

  5. 清理本地仓库并重建(有时候旧 jar 被缓存):

    mvn -U clean package
    mvn dependency:purge-local-repository -DmanualInclude="org.mybatis.spring.boot:mybatis-spring-boot-starter"
    
  6. 如果仍有问题,临时把 @Mapper 换成 @MapperScan + @Mapper 或者用 XML 配置试试,以确认是自动装配器的问题还是 Mapper 本身。

  7. 看是否有重复扫描:多个 @MapperScan 或者同时在 spring.factories 中被重复注册也会出问题。

可运行 Demo

基于 Spring Boot + MyBatis 注解方式,使用 H2 内存数据库,保证“开箱即跑”

下面是一个最小可运行的示例,确认环境是兼容的:Spring Boot(3.x 系列)+ mybatis-spring-boot-starter:3.0.3 + Java 17。

把下面目录结构放到一个 Maven 项目里即可运行。

demo-mybatis/
├─ pom.xml
├─ src/├─ main/├─ java/com/example/demo/│  ├─ DemoApplication.java│  ├─ mapper/UserMapper.java│  └─ model/User.java└─ resources/├─ application.properties└─ schema.sql

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.6</version><relativePath/></parent><groupId>com.example</groupId><artifactId>demo-mybatis</artifactId><version>0.0.1-SNAPSHOT</version><properties><java.version>17</java.version></properties><dependencies><!-- MyBatis Spring Boot Starter (注意版本) --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency><!-- Spring Web(方便启动并观察) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- H2 内存数据库,方便 demo --><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency><!-- 支持 JDBC --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!-- 测试 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

application.propertiessrc/main/resources/application.properties

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MYSQL
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver# MyBatis 配置(若使用 XML mapper,可在这里配置 locations)
mybatis.mapper-locations=classpath*:mapper/*.xml
mybatis.type-aliases-package=com.example.demo.model

这里我们用注解方式的 Mapper,因此 mapper-locations 可以不用配置,但保留也没问题。

schema.sqlsrc/main/resources/schema.sql

Spring Boot 会自动在运行时执行这个 SQL(H2 数据库),创建表。

CREATE TABLE users (id BIGINT PRIMARY KEY,name VARCHAR(100)
);

实体类 User.javasrc/main/java/com/example/demo/model/User.java

package com.example.demo.model;public class User {private Long id;private String name;public User() {}public User(Long id, String name) { this.id = id; this.name = name; }public Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getName() { return name; }public void setName(String name) { this.name = name; }@Overridepublic String toString() {return "User{id=" + id + ", name='" + name + "'}";}
}

Mapper 接口 UserMapper.javasrc/main/java/com/example/demo/mapper/UserMapper.java

package com.example.demo.mapper;import com.example.demo.model.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;@Mapper
public interface UserMapper {@Insert("INSERT INTO users(id, name) VALUES(#{id}, #{name})")void insert(User user);@Select("SELECT id, name FROM users WHERE id = #{id}")User findById(Long id);
}

注意:使用 @Mapper 注解或在启动类上使用 @MapperScan("...mapper") 都可以。这里用了 @Mapper,简单明了。

启动类 DemoApplication.javasrc/main/java/com/example/demo/DemoApplication.java

package com.example.demo;import com.example.demo.mapper.UserMapper;
import com.example.demo.model.User;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}@BeanCommandLineRunner runner(UserMapper userMapper) {return args -> {System.out.println("Inserting a user...");userMapper.insert(new User(1L, "Alice"));User u = userMapper.findById(1L);System.out.println("Found user: " + u);};}
}

运行方式

  1. 把项目代码放好,执行:

    mvn -U clean package
    mvn spring-boot:run
    
  2. 启动日志中你应该看到类似:

    Inserting a user...
    Found user: User{id=1, name='Alice'}
    

如果能成功运行,说明 mybatis-spring-boot-starter:3.0.3 与 Spring Boot 3.1.6 + Java 17 是兼容的(demo 用 H2 避免外部数据库问题)。

其他可能的坑与补充建议

  • JAR 冲突:如果你有别的依赖(例如旧版 mybatis-spring、shaded 的 mybatis),请通过 mvn dependency:tree 找出并 exclusion 掉。

  • Mapper 被重复扫描:不要同时用 @Mapper@MapperScan 再加上自动装配的扫描路径导致重复注册。

  • Spring 版本与 starter 版本不匹配:使用 Spring Boot 的 dependencyManagement 推荐版本,尽量不要手动随意指定各个库版本,除非你很确定兼容性。

  • IDE 的编译缓存:遇到奇怪的 Class/Bean 问题,建议 mvn clean、Invalidate Caches & Restart(IDEA),并再次打包运行。

  • 查看 Version.class 来源:如果怀疑加载了错误版本的 MyBatis,可以在启动代码中打印实现类的 jar 来源:

    System.out.println(org.apache.ibatis.session.SqlSessionFactory.class.getProtectionDomain().getCodeSource().getLocation());
    

    这样能直观看到哪个 jar 被加载。

总结

  • 错误 Invalid value type for attribute 'factoryBeanObjectType': java.lang.String 很大概率是依赖版本/兼容性问题导致 Spring 在解析 Mapper FactoryBean 时读到不符合预期的元数据格式。
  • 最常见、也最有效的解决办法是:mybatis-spring-boot-starter 升级到与 Spring Boot 兼容的版本(比如 3.0.3),或者清理掉冲突的旧版本
  • 通过 mvn dependency:tree、打印 class 来源、清理缓存、对齐 starter 版本可以快速定位并解决问题。
  • 我在文章里给出一个可运行 Demo(Spring Boot + MyBatis 注解 + H2),可以拿来验证你的本地环境是否配置正确。
http://www.dtcms.com/a/385367.html

相关文章:

  • 从 APP 界面设计到用户体验优化:如何让你的应用脱颖而出?
  • RabbitMQ 高可用与集群机制
  • 迎中秋庆国庆,易天假期安排通知
  • IFNet.py代码学习 自学
  • 深度学习之PyTorch基本使用(一)
  • Python 异常处理与文件操作全解析
  • 记一次神通数据库的链接不释放问题
  • FLASK 框架 (关于Flask框架的简单学习和项目实战)
  • Flutter学习项目
  • Linux中报错记录以及libRadtran的安装—Ubuntu
  • 仓颉编程语言青少年基础教程:enum(枚举)类型和Option类型
  • 124.stm32故障:程序下载不能运行,stlink调试时可以正常运行
  • 3.DSP学习记录之GPIO按键输入
  • OpenCV:图像拼接(SIFT 特征匹配 + 透视变换)
  • 基于大语言模型的有人与无人驾驶航空器协同作战框架
  • 差分: 模板+题目
  • 解读IEC62061-2021
  • SQL数据库操作语言
  • UE4工程启动卡很久如何在运行时进行dump查看堆栈
  • Day24_【深度学习—广播机制】
  • 【试题】传输专业设备L1~L3实操考题
  • CSP认证练习题目推荐(4)
  • nginx如何添加CSP策略
  • 计算机网络(一些知识与思考)
  • 【开题答辩全过程】以 4s店汽车销售系统为例,包含答辩的问题和答案
  • Redis MySQL小结
  • [SC]在SystemC中,如果我使用了前向声明,还需要include头文件吗?
  • peerDependencies 和 overrides区别
  • hadoop集群
  • 基于python的PDF分离和管理工具开发详解