Spring configuration properties: Defaults and Reloading

We’re using the spring framework a lot at work, and it’s generally an enormous improvement over our diverse previous practices for configuration and inter-component relations. However, there are two points where Spring seemed to be a step backwards compared to our previous practice, so I set out to fix them. I hope this will be interesting to others as well – this be my christmas gift…

Default values

Using Spring’s PropertyPlaceholderConfigurer, we separate the configuration of our software into an XML file containing the detailed wiring, and a standard Java Properties file containing simple parameters that can be adjusted by customers (such as cache sizes, TCP/IP port numbers, database connect strings, authentication names and passwords).

Now let’s assume some customer has adapted the properties file, while we ship a new version of our software, which introduces new configuration parameters. The customer shouldn’t have to manually merge and extend his property file; instead, the XML file contains reasonable default values for those properties missing from the customer’s properties file.

In out-of-the-box Spring, there are two ways to do this with a PropertyPlaceholderConfigurer: either put a list of default property bindings into the XML file itself, or put them into another Properties file, which may be contained as a resource in the jar file. Stefan Kleineikenscheidt has a good description of this approach.

What I found somewhat inconvenient is that each property name is listed twice: once in the default values, once when it is assigned to some bean property. So here’s how Stefan’s example would look using my DefaultPropertyPlaceholderConfigurer:

<bean id="propertyConfigurer"
    class="net.wuenschenswert.spring.DefaultPropertyPlaceholderConfigurer">
  <property name="location" value="file:custom/my.properties"/>
</bean>

<bean id="mybean">
  <property name="cachesize" value="${my.cache.size=100}"/>
</bean>

What happens here? The property configurer will load the properties from the given location as usual. Then when it comes to replacing a placeholder, and that placeholder is not defined in the properties file, the default value specified after the equals sign is used!

  ${placeholder=defaultvalue}

Reloading properties

When loading configuration properties from a file, our software would regularly check whether the file’s modification date has changed, and reload the properties if necessary.

I’ll go into this more deeply into the next post… until then, I’ll give you the syntax:

<bean id="configproperties" 
     class="net.wuenschenswert.spring.reconfiguration.ReloadablePropertiesFactoryBean">
  <property name="location" value="file:custom/my.properties"/>
</bean>

<bean id="propertyConfigurer" 
     class="net.wuenschenswert.spring.reconfiguration.ReloadingPropertyPlaceholderConfigurer">
  <property name="properties" ref="configproperties"/>
</bean>

<bean id="mybean">
  <property name="cachesize" value="#{my.cache.size=100}"/>
</bean>

The hash mark identifies the property as reloadable; When the file changes, and the value of the property my.cache.size defined inside that file changes, the setter for the cacheSize property is invoked on the singleton bean named “mybean”. Of course this includes default values, as above.

  #{reloadableplaceholder}
  #{reloadableplaceholder=defaultvalue}

And it actually works!

11 thoughts on “Spring configuration properties: Defaults and Reloading”

  1. Maybe the wrong time to write about Java, but I think the DefaultPropertyPlaceholderConfigurer. Have you posted the spring mailing list about this? IMHO this should be part of spring.

    Merry X-MAS,
    -Stefan

  2. Having this in the standard spring distribution would certainly be great. Thanks for the encouragement! I’ll go about it… after christmas.

    Note I’ve added a link to the source code of DefaultPropertyPlaceholderConfigurer. I’ll have to check with my employer about the copyright of the Reloading… source code.

    Cheers,
    Axel

  3. Hi,
    Can you send how Reloading properties works and the Classes you written?

    Thanks,
    Prakash

  4. Definitely. Publishing it fell off the list somehow. Thanks for your interest! It’ll be the next thing on this blog.

  5. It seems that your solutions has a problem in Tomcat 5.x. However, overriding loadProperties in ReloadablePropertiesFactoryBean with this code will correct the problem :

    /**
    * Load properties into the given instance.
    * 
    * @param props
    *            the Properties instance to load into
    * @throws java.io.IOException
    *             in case of I/O errors
    * @see #setLocations
    */
    @Override
    protected void loadProperties(Properties props) throws IOException {
    	if (this.locations != null) {
    		for (int i = 0; i < this.locations.length; i++) {
    				Resource location = this.locations[i];
    				if (logger.isInfoEnabled()) {
    					logger.info("Loading properties file from " + location);
    				}
    				InputStream is = null;
    				try {
    					is = new FileInputStream(location.getFile().getAbsolutePath());
    					if (location.getFilename().endsWith(XML_FILE_EXTENSION)) {
    						this.propertiesPersister.loadFromXml(props, is);
    					} else {
    						if (this.fileEncoding != null) {
    							this.propertiesPersister
    									.load(props, new InputStreamReader(is,
    											this.fileEncoding));
    						} else {
    							this.propertiesPersister.load(props, is);
    						}
    					}
    				} catch (IOException ex) {
    					if (this.ignoreResourceNotFound) {
    						if (logger.isWarnEnabled()) {
    							logger.warn("Could not load properties from "
    									+ location + ": " + ex.getMessage());
    						}
    					} else {
    						throw ex;
    					}
    				} finally {
    					if (is != null) {
    						is.close();
    					}
    				}
    			}
    		}
    	}
    

    Also, we must put the attribute <property name=”daemon” value=”true”></property> of the timer in the dynamic.xml example so Tomcat shuts down properly.

  6. Thanks for the patch! I have posted an update.

    The demon flag should not be necessary if the application context is
    closed when the webapp context is destroyed. This should happen
    automatically if you use a
    ContextLoaderListener or a servlet-specific application context.

  7. You might also be interested in the “reloading” ticket:
    http://jira.springframework.org/browse/SPR-3439

    Turn-around times for spring-based apps are currently quite bad – my IDE knows how to update and reload a class file, but not how to reload a spring bean definition, which ought to be much simpler. It may take a different shape in the end, but if Spring is not supposed to go down as another Java Dinosaur Framework, there has to be some more dynamicity.

  8. Hi,

    I found that your solution to the problem of default values for properties with DefaultPropertyPlaceholderConfigurer is the best I have seen. Both simple and efficient.

    Bravo !

    I use it now, I hope don’t mind !

    Thanks for your creativity

    Jean-Marie Galliot
    System Architect

Comments are closed.