Thursday, April 19, 2012

Initiate current Spring profile from custom properties file

Recently released Spring 3.1 has a very useful new feature named profile. Shortly speaking we can now say that certain bean of group of beans will be deployed only for current profiles or environments. This feature is perfectly explained here.

There is a very simple way to define current profile(s): just specify system property "spring.profiles.active" with -D command line switch:

spring.profiles.active=production

You can even specify several profiles, e.g.

spring.profiles.active=production,oracle

(that probably means that your application is running in production mode and uses to Oracle DB).

You can also set the current profile programmatically:

ctx.getEnvironment().setActiveProfiles("production", "oracle");


or using configuration file:



ctx.getEnvironment().getPropertySources().addFirst(
    new ResourcePropertySource(conf)
)



(where ctx is of type ConfigurableEnvironment.)




The question is only where to write this code when you using starting Spring in web environment? You can define bean that implements ApplicationContextAware interface. The setApplicationContext method declared by this interface is called by container when bean is being initialized. The problem is that this is too late. When this method is called the current profile has been already initialized.

Better way is described here.

We have to define our custom ApplicationContextInitializer and configure it using special  context parameter contextInitializerClasses using web.xml:


<context-param>
    <param-name>contextInitializerClasses</param-name>
    <param-value>com.alexr.spring.ProfilesInitializer</param-value>
</context-param>




Here is how the code of ProfilesInitializer.initialize() looks like.


@Override
public void initialize(ConfigurableApplicationContext ctx) {
    try {
        String profilesSysProp = System.getProperty("spring.profiles.active");
if (profilesSysProp != null) {
        return;
}
String panpwrConfDir = System.getProperty(PANPWR_CONF_PROP);
String confFile = System.getProperty(CONF_PROP);
ctx.getEnvironment().getPropertySources().addFirst(
            new ResourcePropertySource(confFile));
      } catch (IOException e) {
        throw new RuntimeException(e);
   }
}

This simple solution allows initializing of profile using the same configuration file where all other custom parameters are stored. The profile defined in custom file can still be overridden using system property spring.profiles.activeThis is done by if statement that checks whether the property exists.

Conclusions

Profiles is a very useful feature of Spring 3.1. This post shows how to initiate profile using custom properties file.