Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
235 views
Welcome To Ask or Share your Answers For Others

1 Answer

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...