单例Test Container读取application.yml配置异常:username打印始终为空
问题原因分析
你打印的userName始终为null,核心问题是代码执行时机不匹配:
- 类的
static代码块会在类加载阶段立即执行,此时Spring容器还未初始化,更不会调用带@Value注解的setPrivateName方法,所以静态变量userName依然是初始值null。 - 另外你在
@DynamicPropertySource中已经用TestContainers容器自带的用户名覆盖了配置文件中的aa,就算注入成功,后续实际生效的也是容器的用户名。
解决方案
方案1:仅打印配置文件中的用户名
如果只是想验证配置文件的读取,把打印逻辑放到@PostConstruct方法中(该方法会在Spring完成Bean属性注入后执行),同时调整变量和注入方式:
@ActiveProfiles("Testing") @SpringBootTest abstract class AbstractContainerBaseTest { @Container // 用JUnit 5的@Container自动管理容器生命周期,无需手动start() static final MySQLContainer MY_SQL_CONTAINER = new MySQLContainer(); @Value("spring.datasource.username") private String userName; // 改为实例字段,Spring可直接注入私有字段 @PostConstruct public void printConfigUsername() { System.out.println("配置文件中的用户名:" + userName); // 此时已完成注入,可正确打印 } @DynamicPropertySource static void overrideTestProperties(DynamicPropertyRegistry registry){ registry.add("spring.datasource.url", MY_SQL_CONTAINER::getJdbcUrl); registry.add("spring.datasource.username", MY_SQL_CONTAINER::getUsername); registry.add("spring.datasource.password", MY_SQL_CONTAINER::getPassword); } }
方案2:用配置文件的账号启动TestContainers容器
如果想基于配置文件的用户名/密码初始化MySQL容器,需要在Spring上下文初始化完成后再创建容器,可结合@BeforeAll和@ConfigurationProperties实现:
@ActiveProfiles("Testing") @SpringBootTest @ConfigurationProperties(prefix = "spring.datasource") abstract class AbstractContainerBaseTest { private String username; private String password; static MySQLContainer MY_SQL_CONTAINER; @BeforeAll static void initContainer(AbstractContainerBaseTest testInstance) { // 通过测试实例获取已注入的配置参数 MY_SQL_CONTAINER = new MySQLContainer() .withUsername(testInstance.username) .withPassword(testInstance.password); MY_SQL_CONTAINER.start(); } @DynamicPropertySource static void overrideTestProperties(DynamicPropertyRegistry registry){ registry.add("spring.datasource.url", MY_SQL_CONTAINER::getJdbcUrl); registry.add("spring.datasource.username", MY_SQL_CONTAINER::getUsername); registry.add("spring.datasource.password", MY_SQL_CONTAINER::getPassword); } // @ConfigurationProperties需要getter/setter方法 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
内容的提问来源于stack exchange,提问作者Moly Holy
相关产品推荐
相关产品推荐

