Spring Boot测试:替换数据源为Testcontainers管理PGSQL遇循环依赖
核心问题原因
你的DbTestConfig类中存在不必要的循环依赖:类内通过@Autowired注入了DataSource,但同时又通过@Bean方法创建DataSource实例。Spring初始化DbTestConfig时需要先注入DataSource,但DataSource又依赖该类的Bean方法生成,导致循环创建死锁。
分步修复方案
1. 移除导致循环的冗余代码
直接删除DbTestConfig中无用的@Autowired private DataSource dataSource;字段,这是触发循环依赖的直接原因。
2. 改用Spring Boot推荐的动态属性配置(更优雅)
放弃手动创建DataSource Bean,使用@DynamicPropertySource动态覆盖application-test.yml中的数据源配置,让Spring Boot自动配置帮你管理HikariDataSource,避免手动配置的冲突和冗余:
修改后的DbTestConfig:
@TestConfiguration @SpringBootApplication(exclude = { HazelcastAutoConfiguration.class }) @Testcontainers public class DbTestConfig { @Container public static ComposeContainer dockerComposeContainer = new ComposeContainer(new File("../docker/catalog-test.yml")) .withExposedService("db-catalog", 5432) .withRemoveVolumes(false) .withLocalCompose(true) .waitingFor("db-catalog", new DockerHealthcheckWaitStrategy()); @DynamicPropertySource static void configureDataSource(DynamicPropertyRegistry registry) { String host = dockerComposeContainer.getServiceHost("db-catalog", 5432); Integer port = dockerComposeContainer.getServicePort("db-catalog", 5432); // 动态覆盖数据源配置 registry.add("spring.datasource.url", () -> "jdbc:postgresql://" + host + ":" + port + "/db-catalog"); registry.add("spring.datasource.username", () -> "sa"); registry.add("spring.datasource.password", () -> "sa"); } }
3. 简化配置注解
原配置中的@ComponentScan、@EntityScan、@EnableJpaRepositories、@EnableAsync、@EnableTransactionManagement等注解,@SpringBootApplication已经默认包含了核心扫描和配置能力(只要你的测试类和主应用包结构一致),可以直接移除,减少冗余。
保留原application-test.yml的说明
application-test.yml中的数据源配置会被@DynamicPropertySource动态覆盖,你可以保留原配置作为默认值,也可以删除url、username、password这三个会被替换的字段,进一步简化配置。
内容的提问来源于stack exchange,提问作者Serge Iroshnikov

