Thursday 17 November 2011

Using Spring Expression Language for Server Specific Properties

Spring 3.0 introduced Spring Expression Language (SpEL). This post will describe how to use SpEL to load property files which are different for each server your application runs on. It also describes how server specific properties can used without having to use -D.

The problem solved was how can a WAR be deployed onto different servers without having to package up a server specific property file in each archive (or indeed bundle them all in the same WAR file.) Ideally, you would want to drop the WAR file into any environment without having to configure the container or amend the WAR, and if you wanted to change a property, you would change the property file on the server and redeploy the app (or dynamically refresh the cache of properties.)

In this example, our application needs to access a different remote server registry for each env: Dev, Test and Prod. (For ease in this example, our server names are the same as our envionments!)

Therefore we have a properties file for each env/server (dev.properties, test.properties and prod.properties). Could have a local.properties file on each server but prefixing them with a server name helps distinguish them. An example property file is shown below:

rmiRegistryHost=10.11.12.13
rmiRegistryPort=1099

We have a bean which requires these properties, so it's constructor args contain property placeholders:

<bean id="lookupService" class="com.city81.rmi.LookupService" scope="prototype">
  <constructor-arg index="0" value="${rmiRegistryHost}" /> 
  <constructor-arg index="1" value="${rmiRegistryPort}" />
</bean>


For the above bean to be loaded, the properties need to be loaded themselves and this is done via the PropertyPlaceholderConfigurer class. The location and name of the server specific property file is added as one of the locations the configurer uses to search for properties.

The file is in the same location on each server but in order to know what the name is, SpEL is used. By creating a java.net.InetAddress bean, we can access the hostName of the server the application is running on by using SpEL ie #{inetAddress.hostName}. Therefore, this config doesn't have to change between environments.

<bean id="inetAddress" class="java.net.InetAddress" factory-method="getLocalHost">
</bean>
    
<bean id="propertyBean" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="ignoreResourceNotFound" value="false"/>
    <property name="ignoreUnresolvablePlaceholders" value="false"/>
    <property name="locations">
        <list>
            <value>file:/home/city81/resources/#{inetAddress.hostName}.properties</value>
        </list>
    </property>
</bean>


This is a very specific example where the property files are prefixed with the server names but it shows how SpEL can be used to solve a problem which would have taken a lot more work pre Spring 3.0.

1 comment:

  1. Pretty cool -- only just started looking at SpEL/Spring 3, but straight away this can solve a few headaches with multiple config management.
    Thanks!

    Liv

    ReplyDelete

Note: only a member of this blog may post a comment.