Issue
I have a custom starter that other projects depends on, and that starter applies some configurations including a PropertySource
@Configuration
@PropertySource(value = "classpath:application-geoip.yml", factory = YamlPropertySourceFactory.class)
public class CustomStarterAutoConfiguration
{...}
application-geoip.yml contains properties specific to it's business and an enablement value
...
geoip2:
enabled: true
...
The starter provides the geoip beans with condition to above enabled parameter.
@Configuration
@ConfigurationProperties(prefix = "geoip2")
@ConditionalOnProperty(prefix = "geoip2", name = "enabled", havingValue = "true")
public class GeoIP2ConfigurationProperties {...}
@Configuration
@ConditionalOnProperty(prefix = "geoip2", name = "enabled", havingValue = "true")
public class GeoIPConfig {
// define required beans here with dependency to config from above @Configuration bean
}
I ship my starter with this and then create a project depending on this starter.
In my project, when I check above beans (even the property already set to true) in the context I can not see the beans initiated.
Debugged a bit and see that; While annotation ConditionalOnProperty
is being processed, the context does not have the geoip2.enabled set. But If I wait until the app start and listen the ApplicationStartedEvent
event. I can see the property is there.
event.getApplicationContext().getEnvironment().getProperty("geoip2.enabled") returns true.
so If I am assuming it correct, the PropertySource
annotation seems to processed after ConditionalOnProperty
annotation. Not always, but mostly. Depends on who wins the race.
Why I am trying this, I would like to carry the property from core with a default value. then using projects can override it in their own application.yaml files. I treid to add the property on simple project's application.yaml file and this time the property picked up and beans initiated as expected.
Solution
Rather than using @PropertySource
, your custom starter should provide an EnvironmentPostProcessor
implementation that's registered in META-INF/spring.factories
. This post-processor is called once the Environment
has been created but before the application context is refreshed and any beans are created. It should add a PropertySource
to the environment that contains the geoip2
properties. If you position your PropertySource
appropriately, these properties could then be overridden by those in the user's application.yaml
file.
You can learn more in the reference documentation.
Answered By - Andy Wilkinson
Answer Checked By - Clifford M. (JavaFixing Volunteer)