It seems ConditionalOnProperty only works for properties within the classpath like application.properties in the resources folder. I need a property that an end-user can turn on and off via an external property. An example is extremely simple:
Configuration class, reads the external properties. Sys.out to show it's reading the file properly.
@Configuration
@EnableAutoConfiguration
@PropertySource("file:/Users/end.user/MyApp/config/MyApp.properties")
public class PropertyConfigurer {
@Value("${featureOne}")
private String featureOne;
@PostConstruct
public void init() {
System.out.println("FeatureOne : " + featureOne);
}
}
Feature class, this component class will be put in the application context to be able to be used if the property is enabled via ConditionalOnProperty, otherwise the component is never instantiated.
@Component
@ConditionalOnProperty(name="featureOne", havingValue = "true")
public class FeatureOne {
@PostConstruct
public void init() {
System.out.println("Feature initialized");
}
}
As you can imagine I am never seeing "Feature initialized" due to the "featureOne" property not being available to the spring context until after this class has been constructed. If there was some way to force the properties from @PropertySource to be available to the spring context upon class instantiation. Or any other way? I also tried @DependsOn the PropertyConfigurer from FeatureOne but that interestingly didn't work either.
The Spring framework provides the @ConditionalOnProperty annotation precisely for this purpose. In short, the @ConditionalOnProperty enables bean registration only if an environment property is present and has a specific value. By default, the specified property must be defined and not equal to false.
matchIfMissing. public abstract boolean matchIfMissing. Specify if the condition should match if the property is not set. Defaults to false . Returns: if the condition should match if the property is missing Default: false.
The @ConditionalOnMissingBean is one common example that is used to allow developers to 'override' auto-configuration if they are not happy with your defaults. Spring Boot includes a number of @Conditional annotations that you can reuse in your own code by annotating @Configuration classes or individual @Bean methods.
To conditionally create a bean, we must first create an implementation of Condition. The Condition interface contains the matches method which returns a boolean value. Here, the AuditEnabledCondition class is checking whether audit. enabled is true using the Environment properties.
It seems ConditionalOnProperty only works for properties within the classpath like application.properties in the resources folder.
Not exactly. It also works with external files, provided that they are specified as program arguments during running with spring.config.location
option.
--spring.config.location=file:/Users/end.user/MyApp/config/MyApp.properties
The problem is @PropertySource
is being read by org.springframework.context.annotation.ConfigurationClassParser::processPropertySource
method. And @ConditionalOnProperty
is being validated at org.springframework.boot.autoconfigure.condition.OnPropertyCondition::getMatchOutcome
method.
If you were to put a debug at these two places, you will find that getMatchOutcome is executed first and then processPropertySource. And hence your condition doesn't work with @PropertySource
.
But if you were to run your application as java -jar abc.jar --spring.config.location=file:/Users/end.user/MyApp/config/MyApp.properties
, then these properties are added to context.environment and hence @ConditionalOnProperty
works.
If there was some way to force the properties from @PropertySource to be available to the spring context upon class instantiation
I am not sure if there is any way to do this. But given your requirement (I need a property that an end-user can turn on and off via an external property), using spring.config.location
would be a prudent choice.
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