You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring测试中如何在TestContainers启动后创建带自定义参数的@Bean

问题诊断

你当前的实现存在两个核心问题,导致配置无法生效:

  1. 执行时机错误
    你在NoteTagDBInitializer的init代码块中调用Bean注册逻辑,此时Spring上下文已经完成初始化、Bean的创建与注入流程,你后注册的R2dbcEntityTemplate不会替换已经注入到其他组件中的实例,自然无法生效。
  2. 手动注册Bean逻辑冗余
    你手动创建R2dbcEntityTemplate、ConnectionFactory的实现完全跳过了Spring Boot R2dbc的自动配置逻辑,会丢失连接池、事务管理器等内置配置,后续容易出现兼容性问题。
最优解决方案

Spring Boot 2.2.6及以上版本提供的@DynamicPropertySource注解专门用于解决Testcontainers动态端口的配置注入问题,你不需要手动注册任何Bean,直接复用生产环境的自动配置逻辑即可:

实现步骤

  1. 删除你编写的TemplateFactory类,不需要手动创建R2dbc相关Bean
  2. 修改NoteTagDBInitializer,通过@DynamicPropertySource动态注入数据库连接配置,代码如下:
package com.wayfair.samworkgroupsservice.adapter.note

import com.wayfair.samworkgroupsservice.adapter.DBInitializerInterface
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.testcontainers.containers.DockerComposeContainer
import org.testcontainers.containers.wait.strategy.Wait
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers
import java.io.File

@Testcontainers
class NoteTagDBInitializer : DBInitializerInterface {
    @Autowired
    override lateinit var client: R2dbcEntityTemplate

    override val sqlScripts = listOf(
        "db/note/schema.sql",
        "db/note/reset.sql",
        "db/note/data.sql"
    )

    companion object {
        @Container
        val cont: KDockerComposerContainer = KDockerComposerContainer("docker-compose.test.yml")
            .withExposedService(
                "test-db-local_1", 1433,
                Wait.forListeningPort()
            )
            .withLocalCompose(true)

        @JvmStatic
        @DynamicPropertySource
        fun injectDynamicDbProperties(registry: DynamicPropertyRegistry) {
            val dbHost = cont.getServiceHost("test-db-local_1", 1433)
            val dbPort = cont.getServicePort("test-db-local_1", 1433)
            // 替换为你application.yaml中对应的r2dbc配置键即可
            registry.add("spring.r2dbc.url") { "r2dbc:mssql://$dbHost:$dbPort/你的数据库名称" }
            registry.add("spring.r2dbc.username") { "sa" }
            registry.add("spring.r2dbc.password") { "Password123@#?" }
        }

        class KDockerComposerContainer(yamlFile: String) :
            DockerComposeContainer<KDockerComposerContainer>(File(yamlFile))
    }
}

注意事项

  • 确保你的测试类加载了Spring上下文(比如添加了@SpringBootTest、@DataR2dbcTest注解),@DynamicPropertySource才会被识别
  • 该方案完全复用Spring Boot R2dbc的自动配置逻辑,和生产环境的Bean创建逻辑完全一致,不会出现兼容性问题
  • 如果你使用的Spring Boot版本低于2.2.6,可以自定义ApplicationContextInitializer实现动态属性注入,逻辑和上述方案一致

内容的提问来源于stack exchange,提问作者Lucas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 08:54:02