从miku升级到asyncer r2dbc后,SpringBootTest遇DatabaseClient自动配置错误
解决SpringBoot 2.7.10 + Asyncer R2DBC测试中DatabaseClient缺失问题
问题描述
升级SpringBoot到2.7.10版本,同时从miku切换到io.asyncer:r2dbc-mysql:0.9.3依赖,运行带有@SpringBootTest和@AutoConfigureTestDatabase注解的测试时,触发如下错误:
No qualifying bean of type 'org.springframework.r2dbc.core.DatabaseClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
项目通过自定义配置类MySqlConnectionFactories继承AbstractR2dbcConfiguration创建ConnectionFactory,代码如下:
import io.r2dbc.spi.Option; import io.asyncer.r2dbc.mysql.constant.SslMode; import io.asyncer.r2dbc.mysql.constant.TlsVersions; import io.r2dbc.spi.ConnectionFactories; import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; @Configuration @EnableR2dbcRepositories public class MySqlConnectionFactories extends AbstractR2dbcConfiguration { @Value("${spring.datasource.host}") public String host; @Value("${spring.datasource.db}") public String db; @Value("${spring.datasource.username}") public String userName; @Value("${spring.datasource.password}") public String password; @Override @Bean public ConnectionFactory connectionFactory() { ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() .option(ConnectionFactoryOptions.DRIVER, "mysql") .option(ConnectionFactoryOptions.HOST, host) .option(ConnectionFactoryOptions.USER, userName) .option(ConnectionFactoryOptions.PORT, 3306) .option(ConnectionFactoryOptions.PASSWORD, password) .option(ConnectionFactoryOptions.DATABASE, db) .option(Option.valueOf("sslMode"), SslMode.VERIFY_IDENTITY) .option(Option.valueOf("tlsVersion"), TlsVersions.TLS1_2) .option(Option.valueOf("useServerPrepareStatement"), true) .option(Option.valueOf("tcpKeepAlive"), true) // optional, default false .option(Option.valueOf("tcpNoDelay"), true) // optional, default false .build(); return ConnectionFactories.get(options); } }
当前依赖配置:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-r2dbc</artifactId> </dependency> <dependency> <groupId>io.asyncer</groupId> <artifactId>r2dbc-mysql</artifactId> <version>0.9.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> <version>8.0.26</version> </dependency>
解决方案
1. 排除JDBC测试自动配置干扰
@AutoConfigureTestDatabase默认针对JPA配置,会优先初始化JDBC测试数据库,导致R2DBC相关Bean的自动配置被跳过。可以通过两种方式解决:
- 若测试仅关注R2DBC组件,直接使用
@R2dbcTest替代@SpringBootTest - 保留
@SpringBootTest,但排除JDBC相关自动配置并禁用测试数据库替换:@SpringBootTest(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class}) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
2. 显式声明DatabaseClient Bean
AbstractR2dbcConfiguration理论上会自动创建DatabaseClient,但如果自定义配置未触发该逻辑,可在配置类中手动添加:
@Bean public DatabaseClient databaseClient(ConnectionFactory connectionFactory) { return DatabaseClient.create(connectionFactory); }
3. 清理依赖并统一版本
- 移除
mysql-connector-java依赖:R2DBC使用异步驱动,不需要JDBC连接器 - 去掉
r2dbc-mysql的手动版本号,让Spring Boot依赖管理自动匹配兼容版本:<dependency> <groupId>io.asyncer</groupId> <artifactId>r2dbc-mysql</artifactId> </dependency>
4. 确保配置类被扫描
检查MySqlConnectionFactories所在包是否在Spring Boot组件扫描范围内,若不在测试类中可通过@Import(MySqlConnectionFactories.class)显式导入。
内容的提问来源于stack exchange,提问作者so_kirin
相关产品推荐
相关产品推荐

