Skip to content

Introduce DynamicPropertyRegistrar as a replacement for DynamicPropertyRegistry bean support #33501

@philwebb

Description

@philwebb

#32271 introduced the automatic registration of DynamicPropertyRegistry as a bean that can be used in tests, along with support for @DynamicPropertySource on bean methods. This unfortunately caused spring-projects/spring-boot#41839 due to the fact that Spring Boot already registers a DynamicPropertyRegistry.

In hindsight, I think Spring Boot should not have directly used DynamicPropertyRegistry for Testcontainers support, but instead should have created a new interface that deals with the subtle lifecycle issues we're trying to overcome by triggering container events. I would like to change this in Spring Boot 3.4, but it's hard to do in a back compatible way because DynamicPropertyRegistry is not a Spring Boot interface.

Ideally, in Spring Boot 3.4 we would create a new interface and also create a DynamicPropertyRegistry bean that logs a warning telling folks to migrate. With Spring Framework also adding DynamicPropertyRegistry bean support, this is not possible.

Given that there can be very subtle lifecycle issues with using DynamicPropertyRegistry in a bean (you need to ensure that the bean is created before something else accesses the property). I wonder if we can reconsider the way that Spring Framework will handle this. With the current design, it's quite easy to miss that you should annotate your @Bean method with @DynamicPropertySource to ensure that it gets created early enough. It's also quite easy to miss that the registry is updated as a side-effect of creating the bean. One final problem is that it's a little hard to see how you can update a DynamicPropertyRegistry for an existing bean (rather than one you're creating).

I wonder if we might have time consider a dedicated DynamicPropertyRegistrar interface instead? The interface would accept the DynamicPropertyRegistry to be updated.

In code, I anticipate something like this:

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

I'm not 100% sure if this will work, but if it does it would free up the DynamicPropertyRegistrar bean for Spring Boot to create and use to log migration tips. It would also make it impossible to use DynamicPropertyRegistrar and forget to add @DynamicPropertySource. Finally, it would give a good place to document how a DynamicPropertyRegistrar is created early and to be aware of lifecycle issues. Typically, Testcontainer properties aren't a big problem because the Container beans are distinct from the application. For regular app, the lifecycle issues could be very hard to track down.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions