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();
}
}
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).
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.
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 { // ... }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With