Spring Boot: fetching configuration from database
Can anyone offer me some guidance on the best way to achieve this.
I would like to extend Spring Boot's External Configuration so that I have a single method that can be called from anywhere in my expression. This method will retrieve the property value using the key. This method will first poll the database table and if it does not find the specified key, it will then fall back to the PropertySource order described in 1 .
So, I will 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 like this:
foo = configuration.getValue("my.property");
Is there a better way to get around this? Are you missing a Spring Boot feature that I could use?
EDIT: I would like to be able to change property values while the application is running and get these new values.
source to share
I used the Spring EnvironmentPostProcessor function 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 early in spring, you need to create a file spring.factories
and register the environment post processor. This file must be found here:
src/main/META-INF/spring-factories
In content, you need to set your class to spring property:
# Environment Post Processor
org.springframework.boot.env.EnvironmentPostProcessor=com.your.package.ReadDbPropertiesPostProcessor
source to share