Spring Profiles example

spring-conditional

Spring @Profile allow developers to register beans by condition. For example, register beans based on what operating system (Windows, *nix) your application is running, or load a database properties file based on the application running in development, test, staging or production environment.

In this tutorial, we will show you a Spring @Profile application, which does the following stuff :

  1. Create two profiles – dev and live
  2. If profile “dev” is enabled, return a simple cache manager – ConcurrentMapCacheManager
  3. If profile “live” is enabled, return an advanced cache manager – EhCacheCacheManager
Note

  1. Spring has supported @Profile annotation since version 3.1
  2. @Profile is inside spring-context.jar

Tools used :

  1. Spring 4.1.4.RELEASE
  2. Ehcache 2.9.0
  3. JDK 1.7

1. Spring @Profile Examples

This @Profile annotation can be applied at class level or method level.

1.1 Normal Spring Configuration, enable caching, so that Spring will expect a cache manager at runtime.

AppConfig

package com.mkyong.test;

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

@Configuration
@EnableCaching
@ComponentScan({ "com.mkyong.*" })
public class AppConfig {
}

1.2 A dev profile, which returns a simple cache manager concurrentMapCacheManager

CacheConfigDev.java

package com.mkyong.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("dev")
public class CacheConfigDev {

	private static final Logger log = LoggerFactory.getLogger(CacheConfigDev.class);
	
	@Bean
        public CacheManager concurrentMapCacheManager() {
		log.debug("Cache manager is concurrentMapCacheManager");
                return new ConcurrentMapCacheManager("movieFindCache");
        }
	
}

1.3 A live profile, which returns ehCacheCacheManager

CacheConfigLive.java

package com.mkyong.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.ClassPathResource;

@Configuration
@Profile("live")
public class CacheConfigLive {

	private static final Logger log = LoggerFactory.getLogger(CacheConfigDev.class);
	
	@Bean
	public CacheManager cacheManager() {
		log.debug("Cache manager is ehCacheCacheManager");
		return new EhCacheCacheManager(ehCacheCacheManager().getObject());
	}

	@Bean
	public EhCacheManagerFactoryBean ehCacheCacheManager() {
		EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
		cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
		cmfb.setShared(true);
		return cmfb;
	}
	
}

2. Enable @Profile

Few code snippets to show you how to enable a Spring profile.

2.1 For non-web application, you can enable a profile via the Spring context environment.

App.java

package com.mkyong.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {

	public static void main(String[] args) {

	  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
	  //Enable a "live" profile
	  context.getEnvironment().setActiveProfiles("live");
	  context.register(AppConfig.class);
	  context.refresh();
		
	  ((ConfigurableApplicationContext) context).close();

	}
}

Output


DEBUG com.mkyong.test.CacheConfigDev - Cache manager is ehCacheCacheManager

Or, via the system property like this

App.java

package com.mkyong.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.AbstractEnvironment;

public class App {

	public static void main(String[] args) {

	  //Enable a "dev" profile
	  System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, "dev");
	  ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		
	}
}

Output


DEBUG com.mkyong.test.CacheConfigDev - Cache manager is concurrentMapCacheManager

2.2 For web application, defined a context parameter in web.xml

web.xml

	<context-param>
	    <param-name>spring.profiles.active</param-name>
	    <param-value>live</param-value>
	</context-param>

2.3 For web application don’t have web.xml, like servlet 3.0+ container

MyWebInitializer.java

package com.mkyong.servlet3;
 
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
 
public class MyWebInitializer extends
	AbstractAnnotationConfigDispatcherServletInitializer {
 
	//...
	@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		super.onStartup(servletContext);
		servletContext.setInitParameter("spring.profiles.active", "live");
	}
 
}

2.4 For Unit Test, uses @ActiveProfiles

CacheManagerTest.java

package com.mkyong.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.cache.CacheManager;

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

	@Autowired
	private CacheManager cacheManager;
	
	@Test
	public void test_abc() {
		//...
	}
	
}

3. More…

3.1 Spring @Profile can apply at method level.

AppConfig.java

package com.mkyong.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.ClassPathResource;

@Configuration
@EnableCaching
@ComponentScan({ "com.mkyong.*" })
public class AppConfig {

	private static final Logger log = LoggerFactory.getLogger(AppConfig.class);
	
	@Bean
	@Profile("dev")
        public CacheManager concurrentMapCacheManager() {
		log.debug("Cache manager is concurrentMapCacheManager");
                return new ConcurrentMapCacheManager("movieFindCache");
        }
	
	@Bean
	@Profile("live")
	public CacheManager cacheManager() {
		log.debug("Cache manager is ehCacheCacheManager");
		return new EhCacheCacheManager(ehCacheCacheManager().getObject());
	}

	@Bean
	@Profile("live")
	public EhCacheManagerFactoryBean ehCacheCacheManager() {
		EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
		cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
		cmfb.setShared(true);
		return cmfb;
	}
	
}

3.2 You can enable multiple profiles.


	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
	context.getEnvironment().setActiveProfiles("live", "linux");
	//or
	System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, "dev, windows");
web.xml

	<context-param>
	    <param-name>spring.profiles.active</param-name>
	    <param-value>stage, postgresql</param-value>
	</context-param>

	@ActiveProfiles({"dev", "mysql","integration"})

        ((ConfigurableEnvironment)context.getEnvironment())
                   .setActiveProfiles(new String[]{"dev", "embedded"});

Download Source Code

Download It – Spring-Profiles-Example.zip (17 KB)

References

  1. Spring Profiles – Environment Abstraction
  2. Spring Caching And Ehcache Example
  3. Spring MVC – Set active profile

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

Leave a Reply

avatar
newest oldest most voted
Ed Randall
Guest
Ed Randall

Is it possible to select based on some expression of active profiles
eg. @Profile(“!dev”)

Krishna Gangaraju
Guest
Krishna Gangaraju

for all options above we need to change code right ? enabling correct profile
if it is non-web application have to change in Main Class , if it is web application have to change it in web.xml (before pushing code to that particular environment

Jeremy Foster
Guest
Jeremy Foster

For what it’s worth now or for those just seeing these comments you can set Environment variables in your system for the profiles you want active in that environment and then call something like the following depending on your system and code: System.getenv(“SPRING_PROFILES_ACTIVE”)

I have only just found so I am no expert but it saves you from having to constantly change the code.

Paul
Guest
Paul

One more way to set active profile:

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;

public class Initilizer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.getEnvironment().setDefaultProfiles(environmentType);
}
}

In this case you will avoid context refreshing, which is not always a good idea (especially, using spring-integration)

trackback
Spring MVC – How to set active profile

[…] Spring @Profile Examples […]

shruthi
Guest
shruthi

can @Profile annotation accept more than one value? perhaps like @Profile({“dev”,”gamma”})

mkyong
Guest
mkyong

Yes, review the Spring source code, @Profile accept String[].

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
String[] value();
}

ByteFlinger
Guest
ByteFlinger

“The annotation @Profile is disallowed for this location”

I get this is I try to use @Profile on a @Bean level. This must be a Spring 4 feature or something like that as I am using Spring 3.2.9 which as of right now is the latest

mkyong
Guest
mkyong

Not sure about this, Spring @Profile has been available since Spring 3.

Lucky
Guest
Lucky

@Profile annotation are for method and class level only right?

Brahmaiah R
Guest
Brahmaiah R

good one… :)

Chris Nikitas
Guest
Chris Nikitas

Perfect example, simple and to the point!

Exactly what I needed. Thanks a lot!!!