Spring Profiles Java and XML Configuration

In an enterprise application, you can have different configurations for different environments. For example, maybe in development you are developing against an in-memory datasource rather than looking up that same datasource from JNDI in acceptance or production. Or you have to register monitoring infrastructure only when deploying an application into a load testing environment. We can agree that these configurations are endless. This is where spring profiles come into place. You can use spring profiles in order to dynamically load certain bean definitions based on an active profile. In this example we show you both XML and Java Configuration and also look at how we can activate certain profiles for unit testing.

Spring Profiles Java Configuration

First, lets show how to use spring profiles with Java configuration. The following bean is annotated with the @ComponentScan annotation in order to automatically discover other configuration files and spring beans.

package com.memorynotfound.spring.core.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.memorynotfound")
public class AppConfig {

}

Next, the DevelopmentConfigas the name suggests – will be used to configure bean definitions when the development and/or default profiles are active. We can use the @Profile annotation to register the profile with the configuration. In this annotation we can provide a list of profile names.

package com.memorynotfound.spring.core.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import javax.annotation.PostConstruct;

@Configuration
@Profile({"development", "default"})
public class DevelopmentConfig {

    @PostConstruct
    public void init(){
        System.out.println("development profile is set");
    }

}

The ProductionConfigas the name suggests – will be used when the production profile is active.

package com.memorynotfound.spring.core.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import javax.annotation.PostConstruct;

@Configuration
@Profile({"production"})
public class ProductionConfig {

    @PostConstruct
    public void init(){
        System.out.println("production profile is set");
    }

}

This example bootstraps spring configuration using the AnnotationConfigApplicationContext. We set the active profile using the setActiveProfiles() method. Afterwards we register the Java configuration file and refresh the configuration with the refresh() method. After completing this method, the spring container will configure the application with the active profile. When no profile is configured, by default the default profile is set. You can change the default profile using the setDefaultProfiles() method.

package com.memorynotfound.spring.core;

import com.memorynotfound.spring.core.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class RunJavaConfig {

    public static void main(String... args){
        // choosing an active profile
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.getEnvironment().setActiveProfiles("production");
        ctx.register(AppConfig.class);
        ctx.refresh();
        ctx.close();

        // using default profile
        ctx = new AnnotationConfigApplicationContext();
        ctx.register(AppConfig.class);
        ctx.refresh();
        ctx.close();
    }
}

The previous example generates the following output.

production profile is set
development profile is set

Creating a custom @Profile Annotation

You can create your own custom @Profile annotations. Here is an example how to create a custom @Production annotation.

package com.memorynotfound.spring.core.config;

import org.springframework.context.annotation.Profile;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Profile("production")
public @interface Production {

}

You can also add the @Profile annotation on method level. Personally I don’t like this, because it clutters the configuration file to much. But if you need it, nothing is stopping you.

package com.memorynotfound.spring.core.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CombinedConfig {

    @Bean
    @Production
    public String production(){
        return "production profile";
    }

    @Bean
    @Development
    public String developmentHelloWorld(){
        return "development profile";
    }
}

Spring Profiles XML Configuration

If you prefer XML configuration over Java Configuration, you can configure a profile using the profile attribute of the <beans/> element. This attributes takes a list of comma separated values of the profile name. Next, we configure a simple string which outputs the current name of the configuration file. This file is called dev-config.xml.

<?xml version="1.0" encoding="UTF-8"?>
<beans profile="development, default"
       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.xsd">

    <bean id="profile" class="java.lang.String">
        <constructor-arg index="0" value="development"/>
    </bean>

</beans>

Next, the prod-config.xml contains the profile for production. Again, we simply configure a java.lang.String which outputs the current name of the configuration profile.

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

    <bean id="profile" class="java.lang.String">
        <constructor-arg index="0" value="production"/>
    </bean>

</beans>

We bootstrap spring using the GenericXmlApplicationContext and set the active profile using the setActiveProfile() method. Note that we can provide a list of profiles, this allows us to activate multiple profiles at once. Next, we load all the configuration files using a regex as resource location. Finally, when the invocation of the refresh() method successfully completes, the spring container has initialized the application.

package com.memorynotfound.spring.core;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class RunXmlConfig {

    public static void main(String... args){
        // setting an active profile
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.getEnvironment().setActiveProfiles("production");
        ctx.load("*-config.xml");
        ctx.refresh();
        print(ctx);
        ctx.close();

        // using the default active profile
        ctx = new GenericXmlApplicationContext();
        ctx.load("*-config.xml");
        ctx.refresh();
        print(ctx);
        ctx.close();
    }

    private static void print(ApplicationContext ctx){
        String welcome = ctx.getBean("profile", String.class);
        System.out.println("Active profile: " + welcome);
    }
}

The previous code generates the following output.

Active profile: production
Active profile: development

Again, you can also define different profiles in the same configuration 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.xsd">

    <beans profile="development">

    </beans>

    <beans profile="production">

    </beans>

</beans>

Activating Spring Profiles

You can also declaratively provide the default or active profiles using the following system properties.

// setting the active profile
-Dspring.profiles.active="profile1,profile2"

// setting the default profile
-Dspring.profiles.active="default"

In a web application you can specify the default and active profiles using the following servlet context parameters.

<!-- setting the default profile -->
<context-param>
    <param-name>spring.profiles.default</param-name>
    <param-value>development</param-value>
</context-param>

<!-- setting the active profile -->
<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>development</param-value>
</context-param>

Unit Testing with Spring Profiles

For activating a profile in your unit tests, you can use the @ActiveProfiles annotation.

package com.memorynotfound.spring.core.test;

import com.memorynotfound.spring.core.config.AppConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { AppConfig.class })
@ActiveProfiles("production")
public class JavaConfigTest {

    @Test
    public void test_your_application(){
        System.out.println("testing...");
    }
}

The previous JUnit test generates the following output.

production profile is set
testing...

References

Download

You may also like...