Specific environment setting with Spring

There is one issue that people usually have with J2EE deployment. I call it specific environment setting. Imagine that you have several environments that you want to deploy your J2EE application to. For example development, test, stress test, staging or production. For all those environments you need specific settings like JDBC URL, JDBC user name and password, path to a directory for data export etc. The question is where to put such setting. If you store it in the WAR (JAR, EAR, SAR or other AR) you have to create specific archive for every environment.
It is not a big problem, provided you have an automated build. Nevertheless I do not like this solution. I like to have the same archive for all environments. This way I am sure that the application on production is exactly the same as the one I have tested on the test environment. Moreover, there is a problem with passwords. You have to make them part of the build process and effectively publish them by doing so.
One possible solution is to use JNDI. It is probably the best solution if you can use it. But what if you don't use big and heavy J2EE server. What if you use a servlet container like Tomcat or Jetty instead. In this case I have one of my favorite tricks for you. I use Spring configuration similar to the following one:

 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="locations">
		<list>
			<value>
			  classpath:main-config.properties
			</value>
			<value>
			  file:///${user.home}/spring-test.properties
			</value>
		</list>
	</property>
	<property name="ignoreResourceNotFound" value="true"/>
	<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
 </bean>

<bean class="net.krecan.spring.TstBean">
	<property name="property1" value="${property1}"/>
	<property name="property2" value="${property2}"/>
	<property name="property3" value="${property3}"/>
</bean>

Spring tries to load a configuration file from user home directory. If the file is found, properties from the main-config file are overwritten by those found in the spring-test file. And you can even overwrite those by defining a system property with the same name.
I like it. This way every developer can have his own configuration. There is no danger of accidentally committing passwords to a source control system. You can use exactly the same WAR on every environment. It is relatively safe, although some system administrators do not like it. This way you can distribute an application over the internet without forcing users to unpack it, edit a config file and pack it again afterwards.

4 Responses to “Specific environment setting with Spring”

  1. Tomas Vitek Says:

    Hi Lukas, I use similar approach:

    where *.local is not saved in Subversion.

  2. Tomas Vitek Says:

    once again:

    [context:property-placeholder location="classpath*:database.properties.test, classpath*:database.properties.test.local" ]

    where *.local is not saved in Subversion.

  3. Petr Juza Says:

    I also use Spring possibilities for deployment to more target environments and here you can find my solution.

  4. Myšlenky dne otce Fura » Blog Archive » Podcast: Záznam přednášky Pokročilé techniky automatického testování v praxi Says:

    [...] Křečan ve svém postu Specific environment setting with Spring řeší jiným způsobem stejný problém, který rozebírám na své přednášce a který se [...]