How Spring 3.1 Environments & Profiles will make your life better!

My goal of writing one technical blog post per week fell to the wayside around December mainly due to work related project time constraints. I have a four-day weekend and a sparkling new home office, which has to be used for something other than surfing hacker news. Its noon here and I have two hours to produce this blog post so here I go!

The software I write or design generally needs to be deployed in different configurations. These deployment configuration end points can be generalised into the following buckets

  1. Java Enterprise Containers (jboss, weblogic, tomcat, glassfish, etc)
  2. Standalone Java application
  3. GUI Applications
  4. Testing Frameworks

Ignoring GUI Applications for the moment (I might return to these later) the code is often the same between container, standalone and testing. This leads to a key design consideration or philosophy when designing and coding this “type” of software. The code I write needs to run perfectly and untainted in each scenario.

That’s crucial to quality and robustness! The problem is that there are environmentally aware resources that are configured depending on where the code is executed. When I am writing a unit test I will not (I know I could, but I think you are missing the point) have my datasource bound to a JNDI tree. Where as in the container I simple lookup the tree and ask can I have a datasource please.

And frameworks like Spring encourage this form of development, or at least have popularized patterns such as inversion of control. Instead of the executing code configuring the database or queue it is injected as run time and life is good again.

So a blog post to reiterate the same warbling around inversion of control? Not quite, at this point I have a piece of code

public class BusinessClazz implements SomethingReallyImportant {
    private DataSource dataSource;
    @Required
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
}

The datasource is injected and the BusinessClazz is none the wiser about the origination of the datasource. Hey, I’m not the smartest guy in the world, but I’m certainly not the dumbest. I mean, I’ve read books like “J2ee Development Without Ejb” and “Expert one-on-one J2EE design and development”, and I think I’ve understood them. They’re about girls, right? Just Kidding. I create a datasource in spring and inject it

<bean name="myBusinessClazz" class="BusinessClazz">
   <property name="dataSource" ref="dataSource"/>
</bean>

My business service now is agnostic to the datasource origin and can now happily run in any of my deployment end points. But what about the datasource, how do we configure this to run anywhere? We are focusing on the datasource but this example can be applied to any component that changes between environments or runtimes.

A datasource typically requires two pieces of configuration. The first part of the puzzle is where is the database and how should I connect to it. I need hostnames, port numbers, service names, etc.

The second piece of configuration is how is it represented. Here we have a few options. I could create a simple one single connection to the database

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

Or I could use apache pooling to create a pool of connections

<bean id="dataSource" 
   class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"/>
  <property name="url" value="jdbc:myserver"/>
  <property name="username" value="username"/>
  <property name="password" value="password"/>
  <property name="initialSize" value="2"/>
  <property name="maxActive" value="5"/>
  <property name="maxIdle" value="2"/>
</bean>

Or the container manages the connection and we look it up

<jee:jndi-lookup id="dataSource" jndi-name="java:mydatasource"/>

There are many other ways of configuring the datasource but this is enough for illustration purposes. Spring’s PropertyPlaceholderConfigurer class does a great job at handling properties that change between environments.

The problem is how do we seamlessly go between deployment types and pickup different styles of datasources?

Roll your own

This is not an old problem and has been solved in many different ways by many development teams over the last six or seven years. Each team would look at the problem and create a custom way of adding enough intelligence to the code to help alleviate the problem.

One of the biggest drivers behind making code run cleanly inside and outside of the container is to allow developers write unit tests that test true production code.

A typically example of a solution to this problem is to define datasources in a separate context files and create a naming convention to bring order to the chaos. For example if we had three modes of operation we would have three separate context files.

datasources-containerContext.xml
datasources-pooledConnection.xml
datasources-singleConnection.xml

Next comes custom infrastructure code that has to be used at every point of spring initialization throughout your application. It would leverage the ability to use ant style wildcard searches for context files across the deployed classpath.

ClassPathXmlApplicationContext containerContext = 
   new ClassPathXmlApplicationContext("**/**-containerContext.xml");
ClassPathXmlApplicationContext nonContainerContext = 
   new ClassPathXmlApplicationContext("**/**-pooledContext.xml");
ClassPathXmlApplicationContext testingContextContext = 
   new ClassPathXmlApplicationContext("**/**-singleContext.xml");

In a few hours you can have a system that is tolerant of each runtime and the code is engineered to take advantage of this. This roll your own approach has worked for several years but has the major disadvantage that each team and project has a different way of tackling the problem.

Enter Spring Profiles

As of Spring 3.1 there is a solution to this problem (If you do not have an upgrade path for the libraries your project depends on then you have a much larger problem!)

Spring has introduced the notion of Environments and Profiles across the container. Each application context has an Environment object which can be accessed easily

 ClassPathXmlApplicationContext classPathXmlApplicationContext = 
    new ClassPathXmlApplicationContext();
 ConfigurableEnvironment configurableEnvironment = 
    classPathXmlApplicationContext.getEnvironment();

Each environment can have a number of active profiles. Most Spring profile examples talk about profiles being of dev or prod. However I have a Spring solution to the environment type issues my problem is the different profiles for multiple runtimes. But this is the advantages of the implementation you are free to decide how you use it.

By default your beans have no profile and are loaded into the container. So lets start with example. Imagine if this is my current single connection datasource context

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="…">
 <bean id="dataSource" destroy-method="close" 
   class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
   <property name="url" value="jdbc:hsqldb:hsql://localhost"/>
   <property name="username" value="sa"/>
   <property name="password" value=""/>
 </bean>
</beans>

As of Spring 3.0 there is a new xml application context class called GenericXmlApplicationContext which is an alternative to ClassPathXmlApplicationContext and FileSystemXmlApplicationContext.

The advantage of using GenericXmlApplicationContext is that it can be configured completely with setters rather than a single clunky constructor. Just remember to call refresh() once ready to instantiated the container.

Armed with GenericXmlApplicationContext we initialize the container with the following code snippet

GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
 ctx.getEnvironment().setActiveProfiles("standalone");
 ctx.load("*Context.xml");
 ctx.refresh();

Here I set the active profile to standalone. By convention in my project I will consider any code running outside the application container as “standalone” and anything inside the container as “container”. I can set multiple profiles here, for example I could have the following for setting it to standalone and activemq rather than MQSeries

ctx.getEnvironment().setActiveProfiles("standalone", "activemq");

Setting active profiles will have no effect on the current configuration context since I haven’t set a profile on the beans. So we change our configuration context to

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="…" profile="standalone">
  <bean id="dataSource" destroy-method="close" 
   class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
   <property name="url" value="jdbc:hsqldb:hsql://localhost"/>
   <property name="username" value="sa"/>
   <property name="password" value=""/>
 </bean>
</beans>

These beans will now only be initialized if the active profile is set to “standalone”. Profiles are an attribute of beans rather than bean therefore you can not set individual beans to select profiles. In the older versions of Spring this would still leave the problem with multiple files and ant wildcards to select the correct context at runtime.

Spring 3.1 has introduced the ability to nest <beans/> within <beans/>. With a quick refactor we can now have a single datasource context file such as

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="…">
 <beans profile="standalone">  
 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> 
 <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> 
 <property name="url" value="jdbc:hsqldb:hsql://localhost"/> 
 <property name="username" value="sa"/> 
 <property name="password" value=""/> 
 </bean> 
 </beans> 

 <beans profile="container">
 <jee:jndi-lookup id="dataSource" jndi-name="java:mydatasource"/>
 </beans>
</beans>

And I can quickly change profile to container by

ctx.getEnvironment().setActiveProfiles("container");

How to change profiles

As shown above you can change profiles programmatically by coding something like

ctx.getEnvironment().setActiveProfiles("container");

Another way to change the profile is to pass a system parameter at run time

-Dspring.profiles.active="standalone"

But you can also set it as part of the init parameter of your ear/war

<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>

What it means for you?

Hopefully this gives an insight into a new and powerful feature of Spring 3.1 and a feature that has been sorely missed over the 3 major revisions of Spring.

About these ads

9 thoughts on “How Spring 3.1 Environments & Profiles will make your life better!

  1. Hi Diarmuid, nice post.. One question though I see in above when two profiles “standalone” and “container” are declared we have to mention same bean id “datasource” twice. Does that mean we have multiple copies of the beans created in memory, each associated with respective profiles? or they are same single instance shared across two profiles ?

  2. “As of Spring 3.1 there is a solution to this problem (If you do not have an upgrade path for the libraries your project depends on then you have a much larger problem!)”

    That reminds me of something very familiar…. ah yes, my job. I’ll re-read this post in 2016 when we get to spring 3.1.

  3. Hi Diarmuid,

    I have seen your blog and i really like it. We have a website where some of the java geeks write some articles on java technology. Please let me know if you are interested in writing on our website.

    Thanks

  4. Hi Diarmuid,

    Very nice post. Is it possible to change the active profiles after application initialization? For example, I’d like to have a GUI on my web app where I can dynamically change the profile. Would this require the application context to be refreshed? Would there be any pitfalls with this approach?

    Thanks,
    Jonathan

  5. Pingback: Spring 3.1+ : Environments & Profiles | java7notes

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s