Spring Properties Reloaded

Spring Properties Reloaded

Some time ago , I promised I would describe how to make spring configuration properties reloadable.

When using a standard spring PropertyPlaceholderConfigurer, properties will be read from a file, and their values can be referenced using a ${…} macro syntax. The expanded property values are usually assigned to bean properties in the xml application context.

Now what I would like to have is this: When the file changes, the properties should be read again, and the updated values should be assigned to the original beans’ properties. The standard Spring answer would be “shut down the application context and launch a new one”, but often we can be much more flexible without disrupting operation (e.g. changing the size of a cache etc.)

I came up with the following design goals:

  • Syntax and usage should be as close as possible to the non-reloading standard spring variant
  • Not all placeholders should be dynamic - some bean properties cannot meaningfully be changed at runtime, and the configuration should make this appearant.
  • The same conversions should take place during initial configuration, and when a property is reloaded
  • No extra demon threads - the XML configuration should control when files are checked for updates
  • Spring best practices: programming to interfaces, testability.
  • Singleton beans are enough - there’s no point in reconfiguring instances of templates.

As an example, let’s take a bean whose “cachesize” property is configured using a placeholder “my.cache.size” taken from a property file “config.properties”. The standard spring way to describe this looks as follows:

<bean id="configproperties"
      class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  <property name="location" value="file:config.properties"/>
</bean>

<bean id="propertyConfigurer"
     class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="properties" ref="configproperties"/>
</bean>

<bean id="mybean" class="net.wuenschenswert.spring.example.MyBean">
  <property name="cachesize" value="${my.cache.size}"/>
</bean>

The dynamic variant looks very similar, with only some class names changed, and a slightly different placeholder syntax:

<bean id="configproperties"
      class="net.wuenschenswert.spring.Reloadable
PropertiesFactoryBean”>
  <property name=”location” value=”file:config.properties”/>
</bean>

<bean id=”propertyConfigurer”
      class=”net.wuenschenswert.spring.Reloading
PropertyPlaceholderConfigurer”>
  <property name=”properties” ref=”configproperties”/>
</bean>

<bean id=”mybean” class=”net.wuenschenswert.spring.example.MyBean”>
  <property name=”cachesize” value=”#
{my.cache.size}”/>
</bean>

<!– regularly reload property files. –>
<bean id=”timer” class=”org.springframework.scheduling.timer.TimerFactoryBean”>
   …(see complete file
 for details)…
<bean>

If you’re interested - just dive into the code , or download the jar . Thanks to my colleagues at coremedia for discussion and insights - the hacking is all mine, so I take the blame.

I used Spring 1.2.8 plus commons-logging for development (don’t know about licensing, so I’ll rather not bundle the binaries). Try running the example, change the config file and observe the log output. Whoa.

java -cp spring-reloaded.jar:spring.jar:commons-logging.jar   \\
          net.wuenschenswert.spring.example.Main

Implementation

How does it work? In order to get dynamically reloaded properties, we need the following ingredients:

  • a factory bean that detects file system changes
  • an observer pattern for Properties, so that file system changes can be propagated
  • a property placeholder configurer that remembers where which placeholders were used, and updates singleton beans’ properties
  • a timer that triggers the regular check for changed files

The observer pattern is implemented by the interfaces and classes ReloadableProperties, ReloadablePropertiesListener, PropertiesReloadedEvent, and ReloadablePropertiesBase. None of them are especially exciting, just normal listener handling. The class DelegatingProperties serves to transparently exchange the current properties when properties are updated. We only update the whole property map at once, so that the application can avoid inconsistent intermediate states (more on this later).

Now the ReloadablePropertiesFactoryBean can be written to create a ReloadableProperties instance (instead of a Properties instance, as the PropertiesFactoryBean does). When prompted to do so, the RPFB checks file modification times, and if necessary, updates its ReloadableProperties. This triggers the observer pattern machinery.

In our case, the only listener is the ReloadingPropertyPlaceholderConfigurer. It behaves just like a standard spring PropertyPlaceholderConfigurer, except that it tracks all usages of placeholders. Now when properties are reloaded, all usages of each modified property are found, and the properties of those singleton beans are assigned again.

If it doesn’t work for you, I’d love to read your comments. If it does, even more so!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值