Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I delay evaluation of a Spring @Conditional configuration annotation?

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();
    }
}
like image 688
chrylis -cautiouslyoptimistic- Avatar asked May 07 '14 19:05

chrylis -cautiouslyoptimistic-


People also ask

What is @conditional annotation in Spring?

Annotation Type ConditionalIndicates that a component is only eligible for registration when all specified conditions match. A condition is any state that can be determined programmatically before the bean definition is due to be registered (see Condition for details).

What does @configuration annotation do in spring boot?

One of the most important annotations in spring is @Configuration annotation which indicates that the class has @Bean definition methods. So Spring container can process the class and generate Spring Beans to be used in the application. This annotation is part of the spring core framework.

What is ConditionalOnExpression?

The @ConditionalOnExpression annotation allows configurations based on the result of a SpEL expression . Spring will use the marked definition when the SpEL expression evaluated to true @Controller @ConditionalOnExpression("${controller.enabled}) public class WebController { // ... }


1 Answers

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.

like image 171
Andrei Stefan Avatar answered Jan 13 '23 20:01

Andrei Stefan