Spring应用连接MongoDB TestContainer时Netty连接异常排查求助
排查Spring WebFlux应用连接TestContainers MongoDB的Netty异常
问题背景
将Udemy的Maven示例项目转为Gradle后,使用TestContainers启动MongoDB容器时出现Netty连接异常。使用docker-compose部署MongoDB服务时应用可正常连接,已确认配置了spring.data.mongodb.uri的端口映射。
相关配置代码
build.gradle配置
plugins { java id("org.springframework.boot") version "3.4.1" id("io.spring.dependency-management") version "1.1.7" } group = "com.omri" version = "0.0.1-SNAPSHOT" java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } configurations { compileOnly { extendsFrom(configurations.annotationProcessor.get()) } } repositories { mavenCentral() } dependencies { implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive") implementation("org.springframework.boot:spring-boot-starter-webflux") compileOnly("org.projectlombok:lombok") annotationProcessor("org.projectlombok:lombok") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("io.projectreactor:reactor-test") testRuntimeOnly("org.junit.platform:junit-platform-launcher") testImplementation("org.testcontainers:testcontainers:1.20.4") testImplementation("org.testcontainers:junit-jupiter") } dependencyManagement { imports { mavenBom("org.testcontainers:testcontainers-bom:1.20.4") } } tasks.withType<Test> { useJUnitPlatform() }
测试基类BaseTest代码
public abstract class BaseTest { private static final int MONGO_PORT = 27017; private static final String INIT_JS = "/docker-entrypoint-initdb.d/init.js"; private static final String MONGO_URI_FORMAT = "mongodb://job_user:job_password@%s:%s/job"; @Container protected static final GenericContainer<?> mongo = new GenericContainer<>(DockerImageName.parse("mongo")) .withExposedPorts(MONGO_PORT) .withClasspathResourceMapping("data/job-init.js", INIT_JS, BindMode.READ_ONLY) .waitingFor(Wait.forListeningPort()); @DynamicPropertySource static void mongoProperties(DynamicPropertyRegistry registry) { mongo.start(); registry.add("spring.data.mongodb.uri", () -> String.format(MONGO_URI_FORMAT, mongo.getHost(), mongo.getFirstMappedPort())); } }
测试类JobServiceIT代码
@SpringBootTest @AutoConfigureWebTestClient class JobServiceIT extends BaseTest { @Autowired private WebTestClient webClient; @Autowired private Environment env; @Test public void allJobsTest() { System.out.println(env.getProperty("spring.data.mongodb.uri")); /*webClient.get().uri("/jobs/all").exchange() .expectStatus() .is2xxSuccessful() .expectBody().jsonPath("$").isNotEmpty();*/ } }
异常信息
com.mongodb.MongoSocketWriteException: Exception sending message at com.mongodb.internal.connection.InternalStreamConnection.throwTranslatedWriteException(InternalStreamConnection.java:790) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.InternalStreamConnection.sendMessage(InternalStreamConnection.java:675) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.InternalStreamConnection.trySendMessage(InternalStreamConnection.java:507) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.InternalStreamConnection.sendCommandMessage(InternalStreamConnection.java:482) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceiveInternal(InternalStreamConnection.java:440) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.InternalStreamConnection.lambda$sendAndReceive$0(InternalStreamConnection.java:375) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:378) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.CommandHelper.sendAndReceive(CommandHelper.java:100) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.CommandHelper.executeCommand(CommandHelper.java:49) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.InternalStreamConnectionInitializer.initializeConnectionDescription(InternalStreamConnectionInitializer.java:144) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.InternalStreamConnectionInitializer.startHandshake(InternalStreamConnectionInitializer.java:79) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:235) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitor.lookupServerDescription(DefaultServerMonitor.java:219) ~[mongodb-driver-core-5.2.1.jar:na] at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitor.run(DefaultServerMonitor.java:176) ~[mongodb-driver-core-5.2.1.jar:na] Caused by: io.netty.channel.StacklessClosedChannelException: null at io.netty.channel.AbstractChannel$AbstractUnsafe.write(Object, ChannelPromise)(Unknown Source) ~[netty-transport-4.1.116.Final.jar:4.1.116.Final]
排查修复步骤
移除手动启动容器的代码
TestContainers的@Container注解会自动管理容器的启动、停止生命周期,手动调用mongo.start()会导致容器状态异常,直接删除该行代码。替换为专用MongoDB容器类
使用TestContainers提供的MongoDBContainer替代GenericContainer,它能自动处理MongoDB的端口映射、连接字符串生成等细节,避免手动配置错误:import org.testcontainers.containers.MongoDBContainer; public abstract class BaseTest { private static final String INIT_JS = "/docker-entrypoint-initdb.d/init.js"; @Container protected static final MongoDBContainer mongo = new MongoDBContainer(DockerImageName.parse("mongo:latest")) .withClasspathResourceMapping("data/job-init.js", INIT_JS, BindMode.READ_ONLY) .withCommand("--auth"); // 启用认证,匹配初始化脚本中的用户配置 @DynamicPropertySource static void mongoProperties(DynamicPropertyRegistry registry) { registry.add("spring.data.mongodb.uri", mongo::getReplicaSetUrl); } }添加MongoDB TestContainers依赖
在build.gradle的dependencies块中加入专用依赖:testImplementation("org.testcontainers:mongodb")验证初始化脚本路径
确保job-init.js文件放在src/test/resources/data/目录下,保证TestContainers能正确映射到容器内的初始化脚本目录。确认Mongo用户配置匹配
初始化脚本中创建的用户名、密码、数据库名必须和连接字符串中的一致,例如脚本内容需包含:db.createUser({ user: "job_user", pwd: "job_password", roles: [{ role: "readWrite", db: "job" }] });
内容的提问来源于stack exchange,提问作者omri
相关产品推荐
相关产品推荐

