Home > Java > Spring: profiles or not profiles?

Spring: profiles or not profiles?

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.

email
Send to Kindle
Categories: Java Tags:
  1. Roger Parkinson
    April 16th, 2012 at 00:29 | #1

    When I need to do this I keep the data source as JNDI and use a local JNDI library. I define the JNDI name to point to a datasource, which I actually define in a separate XML file. This way I don’t need to change the Spring config file at all.

    I agree that adding testing and other stuff to the deployment config file seems wrong.

  2. April 16th, 2012 at 07:14 | #2

    @Roger Parkinson
    Hi Roger, any chance for a code snippet or two?

  3. Magnus Heino
    April 16th, 2012 at 09:05 | #3

    I found that profiles are highly usable once you switch to javaconfig and start to practice http://martinfowler.com/bliki/FeatureToggle.html

  4. April 16th, 2012 at 10:34 | #4

    I think, evaluating profiles from the test configuration point of view is a bit limiting. There is no good with mixing up test configuration with configuration for prod evironment.

    I find profiles very useful if you have multiple target runtime environments. If users need to select specific runtime configuration during startup, being able to select active profile dynamically is valuable.

    I agree that such requirements were being solved via naming conventions applied on xml files and environment/system variables, and profile configuration today mainly looks like an attempt to tidy up those old solutions. It is certainly not a big leap forward :-)

  5. April 19th, 2012 at 17:43 | #5

    We tried an approach where the binary build and the configuration build of the application is separated. Only during deployment time you will install both and end up with a complete configuration to run the system. For a standalone Java app the step is very easy: include the configuration files in your classpath.

    During testing time you provide the necessary infrastructure Spring beans with a test config (be it Java or XML-style).

    This may look like a bit a special solution only suitable for “standalone Java apps” but I think deploying a “config build” (say: an XML-file containing your data source definition) to your application server works fine as well.

  6. April 21st, 2012 at 10:13 | #6

    I do completely agree with you, there’s no need for profiles to switch between test and production, and you bring into production needless configurations.
    I work with Maven and Spring and in I use 2 different Maven profiles, one for testing purposes and one for production: so I have 2 folders prod and test whit the same config file, let’s say datasources.xml, containing the same bean configured in the 2 different ways as you did before.
    When I test I use the Maven “test” profile, when I package for production I use the Maven “prod” profile.

  1. No trackbacks yet.