Question

I have a Spring @Configuration class that should register a bean when a specific property value is set in the environment. I wrote a custom Condition implementation that checked whether the value was present, and it works when I fire up the application in Spring Boot, but the bean was never registered when running JUnit tests. I debugged the application and determined that the Condition was being evaluated before the PropertySourcesPlaceholderConfigurer was being instantiated.

I modified my Condition to implement ConfigurationCondition and specify evaluation during the REGISTER_BEAN phase. The method is still called before the configurer is instantiated, but the registered bean now comes and goes as I add or remove the property from the properties file.

Is this the best way to reorder the evaluation? Is this what the ConfigurationCondition interface is for, or am I just accidentally getting it to work now?

@Conditional(PropertyCondition.class)
@Configuration
public class PostbackUrlConfiguration {
    @Value("${serviceName.postbackUrl}")
    String postbackUrl;

    @Bean
    public PostbackUrlProvider provider() {
        return new FixedUrlProvider(postbackUrl);
    }
}

 

public class PropertyCondition implements ConfigurationCondition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().containsProperty("serviceName.postbackUrl");
    }

    @Override
    public ConfigurationPhase getConfigurationPhase() {
        return ConfigurationPhase.REGISTER_BEAN;
    }
}

The test configuration is a static class on my test case:

@Configuration
@ComponentScan
@PropertySource("classpath:/postback.properties")
@Import(PostbackUrlConfiguration.class)
public static class TestConfig {
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}
Was it helpful?

Solution

The parsing phase for a @Configuration class involves reading its class definition, populating a collection of Configuration objects (because one @Configuration class may @Import another @Configuration class so these imports are parsed as well), processing @PropertySources, @ImportResources etc.

Processing @PropertySources doesn't, also, load those properties yet. After the parsing phase is done, the @PropertySources properties are loaded. After these are loaded, then the beans' definitions from inside @Configuration classes are registered (REGISTER_BEAN phase).

So, what you see using a ConfigurationCondition with ConfigurationPhase.REGISTER_BEAN phase is expected because those properties are actually available in the Environment at the time when beans' definitions are registered and after the @Configuration class has been parsed. Using just a Condition I believe it doesn't even reach the parsing phase of a @Configuration, the evaluation is done even before that, when the @Configuration class definition is to be registered.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top