SpringBoot+MyBatis报错:Invalid bean definition的原因排查与解决

 更新时间:2025年09月16日 08:44:07   作者:网罗开发  
这篇文章主要为大家详细介绍了SpringBoot+MyBatis报错:Invalid bean definition的原因排查与解决方法,文中的示例代码讲解详细,希望对大家有所帮助

前言

一段非常常见又让人头大的问题: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 问题。

排查步骤

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

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

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

mvn dependency:tree | grep -i mybatis

检查 pom.xml 中是否显式或隐式引入了旧版 mybatis(通过其他 starter/库引入)。

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

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

mvn -U clean package
mvn dependency:purge-local-repository -DmanualInclude="org.mybatis.spring.boot:mybatis-spring-boot-starter"

如果仍有问题,临时把 @Mapper 换成 @MapperScan + @Mapper 或者用 XML 配置试试,以确认是自动装配器的问题还是 Mapper 本身。

看是否有重复扫描:多个 @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.0
           https://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.properties(src/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.sql(src/main/resources/schema.sql)

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

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

实体类User.java(src/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; }

    @Override
    public String toString() {
        return "User{id=" + id + ", name='" + name + "'}";
    }
}

Mapper 接口UserMapper.java(src/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.java(src/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);
    }

    @Bean
    CommandLineRunner 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);
        };
    }
}

运行方式

把项目代码放好,执行:

mvn -U clean package
mvn spring-boot:run

启动日志中你应该看到类似:

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),可以拿来验证你的本地环境是否配置正确。

到此这篇关于SpringBoot+MyBatis报错:Invalid bean definition的原因排查与解决的文章就介绍到这了,更多相关SpringBoot报错Invalid bean definition内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IDEA2024创建Web项目以及配置Tomcat的实现步骤

    IDEA2024创建Web项目以及配置Tomcat的实现步骤

    在Web项目的开发过程中,Tomcat作为一款开源的Servlet容器,扮演着至关重要的角色,本文将详细阐述2024版本的idea配置Tomcat的全过程,下面就来详细的介绍一下
    2025-10-10
  • 手把手教你实现Java第三方应用登录

    手把手教你实现Java第三方应用登录

    本文主要介绍了手把手教你实现Java第三方应用登录,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • 深入理解java重载和重写

    深入理解java重载和重写

    这篇文章主要介绍了Java方法重载和重写原理区别解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2021-07-07
  • 重新启动IDEA时maven项目SSM框架文件变色所有@注解失效

    重新启动IDEA时maven项目SSM框架文件变色所有@注解失效

    这篇文章主要介绍了重新启动IDEA时maven项目SSM框架文件变色所有@注解失效,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 简单实现Java通讯录系统

    简单实现Java通讯录系统

    这篇文章主要为大家详细介绍了如何简单实现Java通讯录系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • 探索分析Redis AOF日志与数据持久性

    探索分析Redis AOF日志与数据持久性

    这篇文章主要为大家介绍了探索分析Redis AOF日志与数据持久性详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • mybatis-flex实现多数据源操作

    mybatis-flex实现多数据源操作

    MyBaits-Flex内置了功能完善的多数据源支持,本文主要介绍了mybatis-flex实现多数据源操作,具有一定的参考价值,感兴趣的可以了解一下
    2024-06-06
  • Spring简明分析Bean作用域

    Spring简明分析Bean作用域

    scope用来声明容器中的对象所应该处的限定场景或者说该对象的存活时间,即容器在对象进入其 相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁这些对象,这篇文章主要介绍了Spring中的Bean作用域,需要的朋友可以参考下
    2022-07-07
  • SpringCloud Eureka服务的基本配置和操作方法

    SpringCloud Eureka服务的基本配置和操作方法

    Eureka是Netflix开源的一个基于REST的服务治理框架,主要用于实现微服务架构中的服务注册与发现,Eureka是Netflix开源的服务发现框架,用于在分布式系统中实现服务的自动注册与发现,本文介绍SpringCloud Eureka服务的基本配置和操作方法,感兴趣的朋友一起看看吧
    2023-12-12
  • 超详细的Java 问题排查工具单

    超详细的Java 问题排查工具单

    这篇文章主要介绍了超详细的Java 问题排查工具单,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01

最新评论