跳到主要内容

使用动态属性源配置上下文

DeepSeek V3 中英对照 Context Configuration with Dynamic Property Sources

Spring TestContext 框架通过 DynamicPropertyRegistry@DynamicPropertySource 注解以及 DynamicPropertyRegistrar API 提供了对动态属性的支持。

备注

动态属性源基础设施最初设计用于允许基于 Testcontainers 的测试中的属性轻松暴露给 Spring 集成测试。然而,这些功能也可以用于任何形式的外部资源,其生命周期在测试的 ApplicationContext 之外管理,或者用于由测试的 ApplicationContext 管理生命周期的 bean。

优先级

动态属性的优先级高于从 @TestPropertySource 加载的属性、操作系统的环境变量、Java 系统属性,或通过应用程序使用 @PropertySource 声明式或编程方式添加的属性源。因此,动态属性可用于选择性地覆盖通过 @TestPropertySource、系统属性源和应用程序属性源加载的属性。

DynamicPropertyRegistry

DynamicPropertyRegistry 用于向 Environment 添加 名称-值 对。值是动态的,并通过 Supplier 提供,仅在解析属性时调用。通常使用方法引用来提供值。以下部分提供了如何使用 DynamicPropertyRegistry 的示例。

@DynamicPropertySource

与应用于类级别的 @TestPropertySource 注解不同,@DynamicPropertySource 可以应用于集成测试类中的 static 方法,以便为集成测试加载的 ApplicationContextEnvironment 中的 PropertySources 集合添加具有动态值的属性。

在集成测试类中使用 @DynamicPropertySource 注解的方法必须是 static 的,并且必须接受一个 DynamicPropertyRegistry 类型的参数。有关更多详细信息,请参阅 DynamicPropertyRegistry 的类级别 Javadoc。

提示

如果你在基类中使用 @DynamicPropertySource,并且发现子类中的测试失败,因为动态属性在子类之间发生了变化,你可能需要在基类上添加 @DirtiesContext 注解,以确保每个子类都能获得带有正确动态属性的独立 ApplicationContext

以下示例使用 Testcontainers 项目来管理 Spring ApplicationContext 外部的 Redis 容器。通过 redis.hostredis.port 属性,被管理的 Redis 容器的 IP 地址和端口可供测试的 ApplicationContext 中的组件使用。这些属性可以通过 Spring 的 Environment 抽象访问,或者直接注入到 Spring 管理的组件中——例如,分别通过 @Value("${redis.host}")@Value("${redis.port}") 注入。

@SpringJUnitConfig(/* ... */)
@Testcontainers
class ExampleIntegrationTests {

@Container
static GenericContainer redis =
new GenericContainer("redis:5.0.3-alpine").withExposedPorts(6379);

@DynamicPropertySource
static void redisProperties(DynamicPropertyRegistry registry) {
registry.add("redis.host", redis::getHost);
registry.add("redis.port", redis::getFirstMappedPort);
}

// tests ...

}
java

DynamicPropertyRegistrar

作为在集成测试类中实现 @DynamicPropertySource 方法的替代方案,你可以在测试的 ApplicationContext 中将 DynamicPropertyRegistrar API 的实现注册为 bean。这样做可以支持一些 @DynamicPropertySource 方法无法实现的额外用例。例如,由于 DynamicPropertyRegistrar 本身是 ApplicationContext 中的一个 bean,它可以与上下文中的其他 bean 进行交互,并注册从这些 bean 中获取的动态属性。

测试的 ApplicationContext 中任何实现了 DynamicPropertyRegistrar 接口的 bean 都会在单例预实例化阶段之前被自动检测并提前初始化,并且这些 bean 的 accept() 方法会被调用,传入一个 DynamicPropertyRegistry,该注册器代表注册者执行实际的动态属性注册。

注意

与其他 bean 的任何交互都会导致这些其他 bean 及其依赖项的急切初始化。

以下示例演示了如何将 DynamicPropertyRegistrar 实现为一个 lambda 表达式,该表达式为 ApiServer bean 注册一个动态属性。可以通过 Spring 的 Environment 抽象访问 api.url 属性,或者直接将其注入到其他 Spring 管理的组件中——例如,通过 @Value("${api.url}"),并且 api.url 属性的值将从 ApiServer bean 中动态获取。

@Configuration
class TestConfig {

@Bean
ApiServer apiServer() {
return new ApiServer();
}

@Bean
DynamicPropertyRegistrar apiPropertiesRegistrar(ApiServer apiServer) {
return registry -> registry.add("api.url", apiServer::getUrl);
}
}
java