SpringBoot+MyBatis報錯:Invalid bean definition的原因排查與解決
前言
一段非常常見又讓人頭大的問題:Spring Boot 項目啟動時報 Invalid bean definition with name 'userMapper' ... Invalid value type for attribute 'factoryBeanObjectType': java.lang.String。你已經(jīng)把網(wǎng)上的各種注解檢查過了,最后發(fā)現(xiàn)把 mybatis-spring-boot-starter 升級到 3.0.3 后問題消失——這是對的。下面把問題的本質(zhì)、常見根因、排查流程和徹底可運行的 Demo(可直接跑)整理成一篇易讀的技術(shù)博客,方便你理解和復用。
摘要
這個錯誤通常不是因為寫錯 @Mapper 注解或 Mapper 接口方法,而是運行時類路徑上的 MyBatis / MyBatis Spring Boot Starter 與當前 Spring Boot 版本不兼容,導致 Spring 在處理 MapperFactoryBean 的 factoryBeanObjectType 屬性時拿到了錯誤的類型(字符串),從而觸發(fā)校驗失敗。解決辦法主要是:對齊依賴版本(升級/降級 mybatis starter)或移除沖突的舊版本,并用 mvn dependency:tree 檢查沖突。
為什么會發(fā)生
Spring 在處理 Mapper 接口時會為每個接口注冊一個 MapperFactoryBean(或者某種 FactoryBean),Spring 會讀取該 FactoryBean 的元信息(factoryBeanObjectType)來做 bean 定義校驗。如果類路徑中某個庫版本不對,或 MapperFactoryBean 的實現(xiàn)不同(返回了字符串而非 Class<?>),Spring 會在啟動階段判斷類型不符合而拋出異常。
常見導致這種問題的根源包括:
mybatis-spring-boot-starter的版本與 Spring Boot 版本不匹配(例如 starter 包里對 Spring API 的使用方式與當前 Spring 版本期望不一致)。- 項目中同時存在多個不同版本的 MyBatis / MyBatis-Spring / mybatis-spring-boot-starter(jar 沖突)。
- 誤把 mapper 的實現(xiàn)類或注解寫得奇怪,導致生成的 bean 元數(shù)據(jù)異常(不常見,相對概率?。?。
你遇到的場景:把 mybatis-spring-boot-starter 從 3.0.0 改為 3.0.3(starter 內(nèi)含 MyBatis 3.5.13)后問題解決,說明確實是版本兼容/bug 問題。
排查步驟
當你看到類似錯誤時,推薦按下面步驟排查,能快速定位問題:
查看完整異常棧,定位是哪個 Bean(userMapper)和哪個 class file。
執(zhí)行 mvn dependency:tree,查找 mybatis / mybatis-spring / mybatis-spring-boot-starter 是否出現(xiàn)多個版本(特別是傳遞依賴沖突)。
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 內(nèi)存數(shù)據(jù)庫,保證“開箱即跑”
下面是一個最小可運行的示例,確認環(huán)境是兼容的:Spring Boot(3.x 系列)+ mybatis-spring-boot-starter:3.0.3 + Java 17。
把下面目錄結(jié)構(gòu)放到一個 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 內(nèi)存數(shù)據(jù)庫,方便 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 會自動在運行時執(zhí)行這個 SQL(H2 數(shù)據(jù)庫),創(chuàng)建表。
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);
};
}
}
運行方式
把項目代碼放好,執(zhí)行:
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 避免外部數(shù)據(jù)庫問題)。
其他可能的坑與補充建議
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,可以在啟動代碼中打印實現(xiàn)類的 jar 來源:
System.out.println(org.apache.ibatis.session.SqlSessionFactory.class.getProtectionDomain().getCodeSource().getLocation());
這樣能直觀看到哪個 jar 被加載。
總結(jié)
- 錯誤
Invalid value type for attribute 'factoryBeanObjectType': java.lang.String很大概率是依賴版本/兼容性問題導致 Spring 在解析 Mapper FactoryBean 時讀到不符合預期的元數(shù)據(jù)格式。 - 最常見、也最有效的解決辦法是:把
mybatis-spring-boot-starter升級到與 Spring Boot 兼容的版本(比如 3.0.3),或者清理掉沖突的舊版本。 - 通過
mvn dependency:tree、打印 class 來源、清理緩存、對齊 starter 版本可以快速定位并解決問題。 - 我在文章里給出一個可運行 Demo(Spring Boot + MyBatis 注解 + H2),可以拿來驗證你的本地環(huán)境是否配置正確。
到此這篇關(guān)于SpringBoot+MyBatis報錯:Invalid bean definition的原因排查與解決的文章就介紹到這了,更多相關(guān)SpringBoot報錯Invalid bean definition內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot3匹配Mybatis3的錯誤與解決方案
- 解決springboot3:mybatis-plus依賴錯誤:org.springframework.beans.factory.UnsatisfiedDependencyException
- 解決SpringBoot搭建MyBatisPlus中selectList遇到LambdaQueryWrapper報錯問題
- 解決springboot3.2集成mybatis-plus3.5.4.1報錯的問題
- Springboot3整合Mybatis-plus3.5.3報錯問題解決
- springboot+mybatis報錯找不到實體類的問題
- SpringBoot集成MybatisPlus報錯的解決方案
相關(guān)文章
IDEA2024創(chuàng)建Web項目以及配置Tomcat的實現(xiàn)步驟
在Web項目的開發(fā)過程中,Tomcat作為一款開源的Servlet容器,扮演著至關(guān)重要的角色,本文將詳細闡述2024版本的idea配置Tomcat的全過程,下面就來詳細的介紹一下2025-10-10
重新啟動IDEA時maven項目SSM框架文件變色所有@注解失效
這篇文章主要介紹了重新啟動IDEA時maven項目SSM框架文件變色所有@注解失效,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-03-03
探索分析Redis?AOF日志與數(shù)據(jù)持久性
這篇文章主要為大家介紹了探索分析Redis?AOF日志與數(shù)據(jù)持久性詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
mybatis-flex實現(xiàn)多數(shù)據(jù)源操作
MyBaits-Flex內(nèi)置了功能完善的多數(shù)據(jù)源支持,本文主要介紹了mybatis-flex實現(xiàn)多數(shù)據(jù)源操作,具有一定的參考價值,感興趣的可以了解一下2024-06-06
SpringCloud Eureka服務的基本配置和操作方法
Eureka是Netflix開源的一個基于REST的服務治理框架,主要用于實現(xiàn)微服務架構(gòu)中的服務注冊與發(fā)現(xiàn),Eureka是Netflix開源的服務發(fā)現(xiàn)框架,用于在分布式系統(tǒng)中實現(xiàn)服務的自動注冊與發(fā)現(xiàn),本文介紹SpringCloud Eureka服務的基本配置和操作方法,感興趣的朋友一起看看吧2023-12-12

