Nicolas Frankel is an IT consultant with 10 years experience in Java / JEE environments. He likes his job so much he writes technical articles on his blog and reviews technical books in his spare time. He also tries to find other geeks like him in universities, as a part-time lecturer. Nicolas is a DZone MVB and is not an employee of DZone and has posted 221 posts at DZone. You can read more from them at their website. View Full User Profile

Spring: Profiles or Not Profiles?

04.20.2012
| 5544 views |
  • submit to reddit
I’m a big user of Spring, and I must confess I didn’t follow all the latest additions of version 3.1. One such addition is the notion of profile.

Context

Profiles are meant to address the case when you use the same Spring configuration across all your needs, but when there are tiny differences. The most frequent use-case encountered is the datasource. For example, during my integration tests, I’m using no application server so my datasource comes from a simple org.apache.commons.dbcp.BasicDataSource configured with URL, driver class name, user and password like so:

<bean id="dataSource">
    <property name="driverClassName" value="${db.driver}" />
    <property name="url" value="${db.url}" />
    <property name="username" value="${db.username}" />
    <property name="password" value="${db.password}" />
</bean>

Note there are other alternatives to BasicDataSource, such as org.springframework.jdbc.datasource.SingleConnectionDataSource or com.mchange.v2.c3p0.ComboPooledDataSource.

In an application server environment, I use another bean definition:

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ds" />

You probably noticed both previous bean definitions have the same name. Keep it in mind, it will play a role in the next section.

My legacy solution

In order to be able to switch from one bean to another in regard to the context, I use the following solution:

  • I separate the datasource bean definition in its own Spring configuration file (respectively spring-datasource-it.xml and spring-datasource.xml)
  • For production code, I create a main Spring configuration file that imports the latter:
    <!--?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="...">
        <import resource="classpath:spring-datasource.xml"/>
        ...
    </beans>
  • For integration testing, I use a Spring Test class as parent (like AbstractTestNGSpringContextTests) and configure it with the ContextConfiguration annotation. @ContextConfiguration has a location attribute that can be set with the location of all needed Spring configuration fragments for my integration test to run.

Besides, as a Maven user, I can neatly store the spring-datasource.xml file under src/main/resources and the spring-datasource-it.xml file under src/test/resources, or in separate modules. Given these, the final artifact only contains the relevant application server datasource bean in my Spring configuration: the basic datapool safely stays in my test code.

The profile solution

Remember when bean identifiers had to be unique across your entire Spring configuration, this is the case no more. With profiles, each bean (or more precisely beans group) can be added an extra profile information so that bean identifiers have to be unique across a profile. This means that we can define two beans with the datasource identifier, and set a profile for each: Spring won’t complain. If we call those profiles integration and application-server, and activate those in the code when needed, this will have exactly the same results. The Spring configuration file will look like this:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">
    ...
    <beans profile="integration">
        <bean id="dataSource">
            <property name="driverClassName" value="${db.driver}" />
            <property name="url" value="${db.url}" />
            <property name="username" value="${db.username}" />
            <property name="password" value="${db.password}" />
        </bean>
    </beans>
    <beans profile="production">
        <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/ds" />
    </beans>
</beans>

Now, the Spring configuration file contains both contexts.

Conclusion

I’m not entirely sure that such a use of profiles brings anything to the table (despite the datasource example being depicted everywhere on the web). Granted, we switched from a build-time configuration to a runtime configuration. But the only consequence I see is that the final artifacts ships with information irrelevant to the environment: it’s bad practice at best, and at worst a security flaw.

Other use-cases could include the need to run the application both on an application server and in the cloud. Even then, I would be a in favor of distinct configuration files assembled at build time. I think I will stay with my legacy approach for the moment, at least until I’m proven wrong or until a case presents itself that can easily be solved by profiles without side-effects.

Published at DZone with permission of Nicolas Frankel, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)