Bean Definition Profiles and PropertySource in Spring 3.1

Spring 3.1 is just around the corner, so it is time to have a look at what is coming. Honestly, I think there are so many changes in this releases, that I would have called this Spring 3.5 instead, but ok. The new features I am going to blog about today are Bean Definition Profiles and Property Sources.

As a Spring 1.2 dude, I have often been in a situation where you needed a Spring bean to be different based on different environments. The most common scenario is this. Lets say you are configuring your MySQL database access like this:


<?xml version="1.0" encoding="UTF-8"?>
<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-3.0.xsd">

<bean id="properties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/>
<property name="locations">
<list>
<value>classpath:app.properties</value>
</list>
</property>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="${app.db.url}"/>
<property name="username" value="${app.db.username}"/>
<property name="password" value="${app.db.password}"/>
<property name="validationQuery" value="SELECT 1 FROM DUAL"/>
</bean>

</beans>


Now when running local unit test, you don't want them to mess with a real MySQL server, even though this is sort of the only way to surface these nasty MySQL integration problems. However, you want unit tests to run super fast, i.e. in memory. So what you are thinking about is something like this:


<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:data"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>


A HSQLDB that runs in memory. Now there are several approaches to switch the Spring beans. What I like to do is to use the bean overriding feature. That is to create a second main file for the ApplicationContext which will re-use the first applicationContext.xml file. Lets call the second file testApplicationContext.xml. It will look like this:


<?xml version="1.0" encoding="UTF-8"?>
<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-3.0.xsd">

<import resource="applicationContext.xml" />

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:data"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>

</beans>


The bean definitions in this file will overwrite the previous bean definitions. The testApplicationContext.xml file is used like this in unit tests:


@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="/testApplicationContext.xml")
public class SomeTest {


All good. This works well whenever you can overwrite the beans. There are alternatives. In the classpath, you could have subdirectories named after your environment, i.e. integration, production etc. Then you write some intelligent bean loader mechanism that dynamically includes the correct files. The same is possible by using <import resource="beans-${environment}.xml" />. Spring 3.1 is addressing the problem and comes with a solution in form of the so called bean definition profiles. It will allow you to do 2 new things. You can specify a profile attribute in a beans element and you are allowed to nest beans-elements, so you can have all profiles in one XML file.


<?xml version="1.0" encoding="UTF-8"?>
<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-3.1.xsd">

<bean id="properties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/>
<property name="locations">
<list>
<value>classpath:app.properties</value>
</list>
</property>
</bean>

<beans profile="testing">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:data"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
</beans>

<beans profile="production">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="${app.db.url}"/>
<property name="username" value="${app.db.username}"/>
<property name="password" value="${app.db.password}"/>
<property name="validationQuery" value="SELECT 1 FROM DUAL"/>
</bean>
</beans>
</beans>


Now you need to tell Spring which profile is active. Spring will be looking for a property called spring.profiles.active, which can be a single profile or a comma-separated list of profiles. In Spring 3.1 each ApplicationContext has a reference to a new Object which implements the new Environment Interface. This Environment instance knows all the active profiles and can therefore select the right beans out of the configuration files. To programmatically set the active profiles you would do:


final ApplicationContext applicationContext = new GenericXmlApplicationContext();

applicationContext.getEnvironment().setActiveProfiles("integration");


IntelliJ 10.5 already supports this by the way. You specify an active bean definition profile and IntelliJ will grey out the sections within the Spring configuration that are not affected by this profile - very cool. Back to the spring.profiles.active property. Spring 3.1 comes also with something new called PropertySource, which is as the name suggests a source for Properties. To identify the value for spring.profiles.active it will go through a hierarchy of property sources. The StandardEnvironment class has a PropertySource for system environment variables and JVM system properties, the latter one being more specific so it will be checked first. If you have a web application, there will also be a PropertySource for properties within the web.xml. This is done through the StandardServletEnvironment. So there are different ways to set spring.profiles.active for your application. You can have this on system level:


export spring.profiles.active=production


or start your application using:


-D spring.profiles.active=production


or have a web.xml like this:


<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>spring.profiles.active</param-name>
<param-value>production</param-value>
</init-param>
</servlet>


These PropertySources are a really great feature. I like them even more than the bean definition profiles. I could imagine that your XML configuration can get a bit messy and hard to read if you use the profiles over excessively. I think I will stick with the bean override stuff for a while and see if the profiles are really better.

Totally unrelated and I don't remember why exactly, but recently I needed a mechanism to copy the properties for a Spring application back into System.properties when the application was loading. I think I used these properties from Spring powered beans but there were some legacy parts that were expecting them to be system properties. Here is a class that did this for me, maybe you find this useful.


import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import java.io.IOException;
import java.util.Properties;

/**
* A {@link PropertyPlaceholderConfigurer} merging loaded {@link Properties} with System {@link Properties}.
*
* Author: reik, 3/15/11
*/
public class SystemPropertiesMergingPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

/**
* Does the same as {@link PropertyPlaceholderConfigurer#mergeProperties()} but additionally merges the properties
* back into {@link System#getProperties()} before returning the loaded {@link Properties}.
*
* @return Properties
* @throws IOException
*/
@Override
protected Properties mergeProperties() throws IOException {
final Properties springProperties = super.mergeProperties();
System.getProperties().putAll(springProperties);
return springProperties;
}
}

When a design smell couldn't be more obvious

Today I was working on a small refactoring which I applied to a HttpServlet that exists in our shared codebase. This Servlet was written in a way which made it almost impossible to extend. A lot of private static methods, communicating with the database or accession filesystem resources, made this class really nice to test - ironically. In order to get anywhere, I initially decided to re-use the code by using the “copy-paste-change” pattern. A few weeks later I changed my mind and decided to make the shared code more extensible by refactoring the methods to be protected non-static. When I was done and I ran the testsuite, I saw that one test was failing.

Here is a snippet of a unit test that someone had written.


public class SomeTest {
private Method logMethod;

@BeforeMethod
public void setup() throws NoSuchMethodException {
logMethod = TheServlet.class.getDeclaredMethod(
"logEvent", new Class[] {
Parameter1.class,
Parameter2.class,
Parameter3.class}
);
}

@Test
public void testLogging() throws Exception {
logMethod.setAccessible(true);

// some set-up

logMethod.invoke(null, parameter1, parameter2, parameter3);

// asserts
}
}


Holy! I have seldom seen crappier code (and I am not even going to talk about having to catch Exception in the test method). Someone was getting a reference to the previously private static method inside the Servlet class, to be able to make it accessible via Reflection and invoke it from the test. Really, a design smell could not be more apparent. If you want to test the method, in that case it was doing some logging to the database, write a collaborator class to do the logging for you, that can be tested in isolation and is injected as a dependency. It is always good to take a step backwards and look at the million things you have to do in order to test stuff. This will most likely guide you to a better design of your software.