November 26
Simple environmental independence with Spring
by Don Brinker
One of the basic problems most projects run into sooner or later is handling multiple environments. Database connections, web service hosts, and other parameters will vary between development, testing, and production environments. Beyond a certain point, editing each of the configuration files becomes too time-consuming and error-prone, and an automatic approach to solve the problem is needed.
A number of approaches have already been well documented, including using multiple Ant targets and using differing Maven profiles for each environment. These all have one basic problem, however – they result in one output (WAR/EAR/JAR file) per environment. Anyone who’s accidentally shipped a test WAR to the production environment (and watched everything break as a result) can attest to how nice it would be to have a single output that can be used in any environment.
For those using the Spring Framework, a simple solution exists to this problem. A fairly commonly used part of the framework is the PropertyPlaceholderConfigurator, which will allow property names to be specified in lieu of values in the Spring configuration files. These property names are replaced with the contents of specified property files at runtime. For example:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:jdbc.properties</value> </list> </property> </bean></beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.connection.driver_class}"/> <property name="url" value="${jdbc.connection.url}"/> <property name="username" value="${jdbc.connection.username}"/> <property name="password" value="${jdbc.connection.password}"/> <property name="defaultAutoCommit" value="false"/> </bean>
Nothing really new here. As specified above, we still need a seperate jdbc.properties file for each environment. This doesn’t really get us any closer to our goal.
However, there’s a little-documented feature of the PropertyPlaceholderConfigurer: system properties can be used when specifying the property file names. When this is the case, the system properties will be evaluated prior to the property files being loaded. This then allows us to create a single definition for all environments:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:jdbc-${env}.properties</value> </list> </property> </bean></beans>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.connection.driver_class}"/> <property name="url" value="${jdbc.connection.url}"/> <property name="username" value="${jdbc.connection.username}"/> <property name="password" value="${jdbc.connection.password}"/> <property name="defaultAutoCommit" value="false"/> </bean>
And voila, we have what we’re looking for. The output WAR can ship with configuration files for each environment – jdbc-dev.properties, jdbc-test.properties, and so forth. As long as the env system property is set prior to starting the application, the same output file can be used in any environment.
Now this isn’t a perfect solution. Configuration files outside the Spring context (such as those used for log4j or ehcache) can not be managed directly by this approach – in order to have separate log settings for each environment, you’ll need to either use one of the above approaches to build multiple outputs, or manage the configuration in the Spring context. More about that some other time…

The Simple environmental independence with Spring by Molecular Voices, unless otherwise expressly stated, is licensed under a Creative Commons Attribution 3.0 Unported License.
David Palmer said on November 26th, 2007
Molecular Voices » Sensitive Properties Files Give You The Willies? said on April 14th, 2008
C. Irwin said on July 14th, 2008
Don Brinker said on July 14th, 2008
Look at your actual error. If the file not found contains your substitution variable name (${env}, in this example) that’s probably what’s wrong.
C. Irwin said on July 14th, 2008
Don Brinker said on July 14th, 2008
C. Irwin said on July 14th, 2008
classpath:jdbc-${SYSTEM_TYPE}.properties