Spring:如何进行透明运行时可更改属性配置

Han*_*örr 6 configuration spring properties

Spring有一个很好的机制PropertyPlaceholderConfigurer,用于将诸如超时,JDBC Urls等值注入Spring bean以进行配置.是否有一种合理的方法来处理可在运行时更改的配置值?

更新:使用Spring 3.1,有一种很好的方法可以通过PropertySource包含非静态配置源,例如数据库.一些ApplicationContexts提供了一种原则上能够处理不断变化的配置值的刷新机制.然而,它首先停止应用程序,然后创建所有bean新鲜,然后再次启动应用程序上下文.但是,出于我们的目的,我需要一种透明地执行此操作的方法,以便服务器正确处理当前正在运行的请求.

执行此操作的另一个想法是在配置更改时创建新对象的自定义Scope.遗憾的是,提供给Scope的ObjectFactory使用了预处理的bean定义,因此不会从配置中重新读取占位符.因此,创建的对象具有相同的配置.:-(

Han*_*örr 2

下面的代码有点奇怪但是有效。您创建一个名为 name 的自定义范围reconfigurable,只要发生配置更新,该范围就会丢弃在该范围内创建的所有 bean。因此,配置更改后将创建一个新的 bean。

实际的配置值必须通过 spring 表达式语言检索,因为普通 ${} 语法和 PropertyOverrideConfigurer 的值似乎都永久固定在 BeanDefinition 中。具有可重新配置属性的 bean 的 bean 声明someProperty如下所示:

<bean class="blablu.Testbean" scope="reconfigurable"
  p:someProperty="#{ config['configexplicit']}">
  <aop:scoped-proxy />
</bean>
Run Code Online (Sandbox Code Playgroud)

您需要使用 aop:scoped-proxy,以便使用此 bean 的 bean 始终从自定义范围中检索最新配置的 bean。

声明属性@Value也有效;如果使用组件扫描,则需要使用注释声明范围

@Scope(value="reconfigurableScope", proxyMode=ScopedProxyMode.TARGET_CLASS)
Run Code Online (Sandbox Code Playgroud)

如果您关心细节:范围的基本思想是:

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();
    }

}
Run Code Online (Sandbox Code Playgroud)

加上一些线程安全和清理的东西:被删除的 bean 需要稍后在应用程序上下文关闭时销毁。