Home > OS >  Spring Boot Race Condition between PropertySource and ConditionalOnProperty
Spring Boot Race Condition between PropertySource and ConditionalOnProperty

Time:08-12

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.

CodePudding user response:

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.

  • Related