I have defined some external properties in my main class as follows:
@PropertySources({
@PropertySource(value = "classpath:application.properties", ignoreResourceNotFound = true),
@PropertySource(value = "file:/opt/app/conf/database.properties", ignoreResourceNotFound = true),
@PropertySource(value = "file:/opt/app/conf/overrides.properties", ignoreResourceNotFound = true)
})
For some of the properties I would like to do some post processing, for example encrypting or enrichment before they are actually used by any beans. One such property is spring.datasource.password
I have done the following:
ApplicationContextInitializer<ConfigurableApplicationContext> and tried to process those properties in the initialize() methodpublic class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
String value = environment.getProperty("spring.datasource.password");
System.out.println("The value in initializer is " + value);
System.out.println("The database url in initializer is " + environment.getProperty("spring.datasource.url"));
System.out.println("The database username in initializer is " + environment.getProperty("spring.datasource.username"));
// .. other code
}
}
and included the above class in the META-INF/spring.factories as follows:
org.springframework.context.ApplicationContextInitializer=com.myapp.MyApplicationContextInitializer
I am seeing null values in all of the above properties that are printed though both database.properties and overrides.properties are present. They are the very first statements to be printed (even before the banner)
org.springframework.boot.env.EnvironmentPostProcessor and adding in META-INF/spring.factories asorg.springframework.boot.env.EnvironmentPostProcessor=com.myapp.PropertiesProcessor
But still, I get the same null value.
Interestingly, when I pass in the
-Dspring.config.location="file:/opt/app/conf/database.properties, file:/opt/app/conf/overrides.properties"system property before executing the war, it works i.e. the values are printed.
But I do not want to manually pass in the system property at runtime. Is there a way to do it? What is wrong with my code or approach. Are there any other ways of doing the post-processing before actually creating the beans?
I solved similar problem by adding property source with highest precedence.
META-INF/spring.factories with content:org.springframework.boot.env.EnvironmentPostProcessor=
com.example.SettingsPropertiesAddingPostProcessor
public class SettingsPropertiesAddingPostProcessor implements EnvironmentPostProcessor {
private static final String SETTINGS_CONFIG_PATH = "/tmp/settings.properties";
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
File settingsFile = new File(SETTINGS_CONFIG_PATH);
if (!settingsFile.exists()) {
log.debug("Config file not found, skipping adding custom property source");
return;
}
log.debug("Config file found, adding custom property source");
Properties props = loadProperties(settingsFile);
MutablePropertySources propertySources = environment.getPropertySources();
propertySources.addFirst(new PropertiesPropertySource("settings-source", props));
}
private Properties loadProperties(File f) {
FileSystemResource resource = new FileSystemResource(f);
try {
return PropertiesLoaderUtils.loadProperties(resource);
} catch (IOException ex) {
throw new IllegalStateException("Failed to load local settings from " + f.getAbsolutePath(), ex);
}
}
}
That should be all.
Following the advice of @M. Deinum, regarding using "spring.config.additional-location", I have made a workaround as follows:
@SpringBootApplication
@EnableSwagger2
public class MyApp extends SpringBootServletInitializer {
public static void main(String[] args) {
System.setProperty("spring.config.additional-location", "file:/opt/app/conf/database.properties, file:/opt/app/conf/overrides.properties");
SpringApplication springApplication = new SpringApplication(MyApp.class);
springApplication.run(args);
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
System.out.println("Setting properties onStartup");
System.setProperty("spring.config.additional-location", "file:/opt/app/conf/database.properties, file:/opt/app/conf/overrides.properties");
super.onStartup(servletContext);
}
}
I have called the System.setProperty() in the onStartup() method of the SpringBootServletInitializer by overriding it as above and then invoked the super class' onStartup()
The latter part i.e. setting system property in onStartup method helps when the application is deployed in a web container like Tomcat.
Note: We can also append the properties to spring.config.additional-location instead of set so that other additional locations can also be added during runtime.
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