Spring Boot: Retrieving configuration from a database
I have used the EnvironmentPostProcessor spring feature to do this.
You need to create a class like this:
public class ReadDbPropertiesPostProcessor implements EnvironmentPostProcessor {
/**
* Name of the custom property source added by this post processor class
*/
private static final String PROPERTY_SOURCE_NAME = "databaseProperties";
/**
* Adds Spring Environment custom logic. This custom logic fetch properties from database and setting highest precedence
*/
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Map<String, Object> propertySource = new HashMap<>();
try {
// Build manually datasource to ServiceConfig
DataSource ds = DataSourceBuilder
.create()
.username(USERNAME) // replace with your config
.password(PASSWORD) // replace with your config
.url(DATASOURCE-URL)// replace with your config
.driverClassName(DRIVER) // replace with your config
.build();
// Fetch all properties
PreparedStatement preparedStatement = ds.getConnection().prepareStatement("SELECT name, value FROM propertyConfig WHERE service = ?");
preparedStatement.setString(1, APP_NAME);
ResultSet rs = preparedStatement.executeQuery();
// Populate all properties into the property source
while (rs.next()) {
String propName = rs.getString("name");
propertySource.put(propName, rs.getString("value"));
}
// Create a custom property source with the highest precedence and add it to Spring Environment
environment.getPropertySources().addFirst(new MapPropertySource(PROPERTY_SOURCE_NAME, propertySource));
} catch (Exception e) {
throw new RuntimeException("Error fetching properties from db");
}
}
}
Since you need to run this class at a very early stage of spring, you need to create the file spring.factories
and register your environment post processor. This file needs to be located here:
src/main/resources/META-INF/spring.factories
In the content you need to set your class to the spring property:
# Environment Post Processor
org.springframework.boot.env.EnvironmentPostProcessor=com.your.package.ReadDbPropertiesPostProcessor
Related videos on Youtube
mip
Updated on June 15, 2022Comments
-
mip almost 2 years
Can anyone offer me some guidance on the best way for me to achieve this goal.
I'd like to extend the Spring Boot Externalized Configuration so that I have a single method which can be called from anywhere in my application. This method will retrieve a property value using a key. This method will first interrogate a database table and if it does not find the specified key it will then fall back on the PropertySource order described in 1.
So I'd have a service similar to:
@Service public class ConfigurationService { private final ConfigurationRepository configurationRepository; @Autowired public ConfigurationService(ConfigurationRepository configurationRepository) { this.configurationRepository = configurationRepository; } public String getValue(String key) { Configuration configuration = configurationRepository.findOne(key); // Add something here to get the property from application.properties if the key does not exist in the db return configuration == null ? null : configuration.getValue(); } }
Which I can use as follows:
foo = configuration.getValue("my.property");
Is there a better way of going about this? Am I missing a Spring Boot feature that I could utilise?
EDIT: I'd like to be able to change the values of the properties while the application is running and have these new values picked up.
-
chrylis -cautiouslyoptimistic- almost 9 yearsDepending on how large your project/deployment is, this sounds like a potential case for Spring Cloud Config.
-
M. Deinum almost 9 yearsWrite a
PropertySource
that is backed by the database, that way it just integrates with the rest of the system. Or simply write anApplicationInitializer
which loads all the properties from a database, wrap them in aPropertiesPropertySource
and add them to the environment. At least you don't want to go calling this method around the whole place you want to integrate with the default mechanisms.
-