Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring: how to do transparent runtime changeable property configuration

Spring has the nice mechanism PropertyPlaceholderConfigurer for injecting values like timeouts, JDBC Urls and so forth into Spring beans for configuration purposes. Is there a sensible way to handle configuration values that can change at runtime?

UPDATE: With Spring 3.1 there is a nice way to include non-static configuration sources such as the database via PropertySources. Some ApplicationContexts provide a refresh mechanism that is in principle able to handle changing configuration values. However it stops the application first, then creates all beans fresh and then starts the application context again. However, for our purposes I would need a way to do this transparently, such that the server correctly handles currently running requests.

Another idea to do this would be a custom Scope that creates fresh objects when the configuration changes. Unfortunately the ObjectFactory provided to the Scope uses a preprocessed bean definition, such that the placeholders are not read anew from the configuration. Thus the created objects have the same configuration. :-(

like image 297
Hans-Peter Störr Avatar asked Apr 02 '12 09:04

Hans-Peter Störr


3 Answers

Unfortunately configuration from properties files is static and happens at startup. What I am typically doing is exposing dynamic attributes via jmx:

@ManagedResource
@Service
public class BusinessService {

    @ManagedAttribute
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void businessMethod() {
        //use age...
    }

}

Remember to add:

<context:mbean-export/>

To your configuration. Now you can access and change that attribute via jconsole or any other JMX client. See also: 23.3.2 Using Source-Level Metadata (JDK 5.0 annotations).

like image 194
Tomasz Nurkiewicz Avatar answered Sep 23 '22 02:09

Tomasz Nurkiewicz


The following is a little odd but works. You create a custom scope named reconfigurable that throws away all beans created in that scope whenever a configuration update occurs. Thus, a fresh bean will be created after a configuration change.

The actual configuration values have to be retrieved via spring expression language since the values for both the normal ${} syntax nor PropertyOverrideConfigurer seem to be permanently fixed in the BeanDefinition. A bean declaration for a bean with a re-configurable property someProperty looks like this:

<bean class="blablu.Testbean" scope="reconfigurable"
  p:someProperty="#{ config['configexplicit']}">
  <aop:scoped-proxy />
</bean>

You need to use aop:scoped-proxy such that beans that use this bean always retrieve the freshest configured bean from the custom scope.

Declaring properties with @Value also works; if you use component scan you need to declare the scope with the annotation

@Scope(value="reconfigurableScope", proxyMode=ScopedProxyMode.TARGET_CLASS)

If you care for details: the basic idea of the scope is:

public class ReconfigurableScope implements Scope {

    private final Map<String, Object> nameToObjectMap = new ConcurrentHashMap<String, Object>();

    public Object get(final String name, final ObjectFactory<?> objectFactory) {
        Object bean = nameToObjectMap.get(name);
        if (null == bean) {
            bean = objectFactory.getObject();
            nameToObjectMap.put(name, bean);
        }
        return bean;
    }

    // called from outside on each configuration change
    public void update(final ConfigurationObservable observable, final Object arg) {
        nameToObjectMap.clear();
    }

}

Plus some thread safety and cleanup stuff: the removed beans need to be destroyed a little later and on application context close.

like image 30
Hans-Peter Störr Avatar answered Sep 23 '22 02:09

Hans-Peter Störr


There is a running example of what you're trying to accomplish here: https://github.com/ldojo/spring-cloud-config-examples

It demonstrates how a Spring Cloud Config Server and a client service can communicate over Spring Cloud Bus, and the client's configuration properties can change at runtime when there is a configuration change in the Config Server's repo.

like image 38
Lev Avatar answered Sep 26 '22 02:09

Lev