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 DevelopmentConfig
– as 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 ProductionConfig
– as 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...
nice !!! thankyou.