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.

+3


source to share


1 answer


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

      

+2


source







All Articles