Spring Profiles example
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 :
- Create two profiles –
dev
andlive
- If profile “dev” is enabled, return a simple cache manager –
ConcurrentMapCacheManager
- If profile “live” is enabled, return an advanced cache manager –
EhCacheCacheManager
- Spring has supported @Profile annotation since version 3.1
- @Profile is inside spring-context.jar
Tools used :
- Spring 4.1.4.RELEASE
- Ehcache 2.9.0
- 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.
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
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
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.
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
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
<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
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
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.
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");
<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"});
Is it possible to select based on some expression of active profiles
eg. @Profile(“!dev”)
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
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.
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)
can @Profile annotation accept more than one value? perhaps like @Profile({“dev”,”gamma”})
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();
}
“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
@Profile annotation are for method and class level only right?
@Profile annotation is valid together with @Component or @Configuration ref
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
Not sure about this, Spring @Profile has been available since Spring 3.
good one… 🙂
Perfect example, simple and to the point!
Exactly what I needed. Thanks a lot!!!
Jestem fanem Sculpting Miniatures Trzebnica poczta kwiatowa