1. 问题现象与背景分析
最近在将项目从Spring Boot 2.x升级到Spring Boot 3.x时,集成MyBatis-Plus遇到了一个典型错误:
code复制Bean named 'ddlApplicationRunner' is expected to be of type 'org.springframework.boot.Runner'
but was actually of type 'org.springframework.beans.factory.support.NullBean'
这个错误发生在应用启动阶段,核心矛盾点是Spring容器期望找到一个类型为Runner的bean,但实际获取到的却是一个NullBean。这种情况通常发生在:
- 版本不兼容:Spring Boot 3.x与MyBatis-Plus的某些版本存在兼容性问题
- 自动配置冲突:框架间的自动配置机制产生了冲突
- 依赖传递问题:间接依赖引入了不兼容的版本
2. 根本原因深度解析
2.1 Spring Boot 3的自动配置变更
Spring Boot 3对自动配置机制做了重大调整,特别是对ApplicationRunner和CommandLineRunner的处理方式。在Spring Boot 2.x中,这些runner的注册相对宽松,而Spring Boot 3.x引入了更严格的类型检查。
2.2 MyBatis-Plus的DDL处理机制
MyBatis-Plus从3.4.0版本开始引入了DdlApplicationRunner,这是一个自动执行SQL脚本的组件。当同时满足以下条件时会出现问题:
- 使用了
@MapperScan注解 - 配置了
mybatis-plus.global-config.db-config.schema属性 - MyBatis-Plus版本低于3.5.5
2.3 版本兼容性矩阵
经过实际测试,各版本组合的表现如下:
| Spring Boot版本 | MyBatis-Plus版本 | 是否报错 |
|---|---|---|
| 2.7.x | 3.4.0-3.5.4 | 否 |
| 3.0.x | 3.4.0-3.5.4 | 是 |
| 3.0.x | 3.5.5+ | 否 |
| 3.1.x | 3.5.5+ | 否 |
3. 完整解决方案
3.1 版本升级方案(推荐)
这是最彻底的解决方案,只需修改pom.xml:
xml复制<properties>
<mybatis-plus.version>3.5.5</mybatis-plus.version>
</properties>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
</dependencies>
3.2 临时解决方案
如果暂时无法升级MyBatis-Plus,可以通过排除自动配置:
java复制@SpringBootApplication(exclude = {
MybatisPlusAutoConfiguration.class
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
然后手动配置必要的bean,但这会失去部分便利性。
3.3 配置调整方案
关闭MyBatis-Plus的DDL自动执行功能:
yaml复制mybatis-plus:
global-config:
db-config:
schema: ""
ddl-runner: false
4. 问题排查全流程
4.1 错误日志分析
完整的错误堆栈通常如下:
code复制org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'ddlApplicationRunner':
Bean named 'ddlApplicationRunner' is expected to be of type 'org.springframework.boot.Runner'
but was actually of type 'org.springframework.beans.factory.support.NullBean'
关键信息解读:
BeanCreationException:bean创建失败expected type与actual type不匹配NullBean表示Spring尝试创建bean但最终得到了null
4.2 调试技巧
- 在
org.springframework.boot.SpringApplication#prepareContext方法设断点 - 查看
BeanDefinitionRegistry中ddlApplicationRunner的定义 - 检查
MybatisPlusAutoConfiguration的条件装配情况
4.3 依赖树检查
使用Maven命令检查依赖冲突:
bash复制mvn dependency:tree -Dincludes=com.baomidou:mybatis-plus*
重点关注是否有旧版本的MyBatis-Plus被间接引入。
5. 升级后的验证步骤
5.1 基础功能验证
- 启动应用,检查是否报错
- 执行简单的CRUD操作
- 验证分页插件是否正常工作
5.2 高级功能验证
- 多数据源配置
- 乐观锁功能
- 动态表名功能
- SQL注入器自定义
5.3 性能测试
特别注意:
- 连接池配置是否生效
- 二级缓存行为是否符合预期
- 批量操作性能
6. 相关配置优化建议
6.1 推荐配置项
yaml复制mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
global-config:
db-config:
id-type: auto
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
6.2 性能优化配置
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
7. 常见连带问题及解决方案
7.1 升级后出现BeanDefinitionStoreException
如果修改MyBatis-Plus版本后出现:
code复制org.springframework.beans.factory.BeanDefinitionStoreException
解决方案:
- 检查Spring Boot版本是否与MyBatis-Plus兼容
- 推荐使用Spring Boot 3.1.x系列
7.2 SQL语法不兼容问题
升级后可能出现SQL语法问题,这是因为:
- MyBatis-Plus 3.5+改进了SQL生成逻辑
- 对某些数据库方言的支持有变化
解决方案:
- 检查生成的SQL语句
- 必要时自定义
ISqlInjector
7.3 分页插件失效
如果发现分页不生效:
- 检查是否配置了分页插件
- 新版需要显式配置:
java复制@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
8. 最佳实践建议
- 版本锁定:在父pom中锁定MyBatis-Plus版本
- 逐步升级:先升级MyBatis-Plus,再升级Spring Boot
- 测试覆盖:
- 单元测试覆盖主要Mapper方法
- 集成测试验证启动过程和基础功能
- 监控配置:添加SQL监控和性能统计
我在实际项目中发现,使用Spring Boot 3.1.5 + MyBatis-Plus 3.5.5的组合最为稳定。对于复杂的多模块项目,建议先在一个非核心模块进行验证,确认无误后再全量升级。
