Spring Profiles Example

By Arvind Rai, December 02, 2023
Spring @Profile enables a component to be registered when specified profiles are active. A profile can be activated programmatically or declaratively. A component can have more than one profile name or a profile expression. The component will be registered if specified profiles are active or profile expression returns true. The @Profile annotation can be used with @Component, @Service, @Repository, @Controller, @Configuration and @Bean annotations. To define profile in XML configuration, Spring provides profile attribute in <beans> tag.
To activate a profile programmatically, we need to use setActiveProfiles method from ConfigurableEnvironment. To activate a profile declaratively we need to set spring.profiles.active property as a JVM system property or as an environment variable or as a Servlet context parameter in web.xml file.

1. @Profile with @Configuration

We will use here @Profile with @Configuration annotation. For the example, we will create three profiles that are prod, dev and test. @Profile annotation is used with @Configuration as following.
1. JavaConfig for production environment.
ProdEnvConfig.java
@Configuration
@Profile("prod")
public class ProdEnvConfig {
  @Bean
  public User getUser(){
	return new User(100, "Prod User");
  }
} 
User.java
public class User {
   public Integer id;
   public String name;
   public User(Integer id, String name){
	this.id = id;
	this.name = name;
   }
} 
2. JavaConfig for development environment.
DevEnvConfig.java
@Configuration
@Profile("dev")
public class DevEnvConfig {
   @Bean
   public User getUser(){
      return new User(200, "Dev User");
   }
} 
3. JavaConfig for testing environment.
TestEnvConfig.java
@Configuration
@Profile("test")
public class TestEnvConfig {
   @Bean
   public User getUser(){
      return new User(300, "Test User");
   }
} 
We can activate the required profile programmatically as following. Here we are activating production environment profile.
SpringProfileDemo.java
public class SpringProfileDemo {
   public static void main(String[] args) {
       AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
       ctx.getEnvironment().setActiveProfiles("prod");
       ctx.scan("com.concretepage.config");
       ctx.refresh();
       User user = ctx.getBean(User.class);
       System.out.println("id:"+user.id +", Name:"+ user.name );
   }
} 
Output
id:100, Name:Prod User 
"com.concretepage.config" is the package which contains all the JavaConfig files.
Now activate development environment profile.
ctx.getEnvironment().setActiveProfiles("dev"); 
Output
id:200, Name:Dev User 
Now activate testing environment profile.
ctx.getEnvironment().setActiveProfiles("test"); 
Output
id:300, Name:Test User 

2. Using Profile with XML Configuration

To define a profile in XML configuration, Spring provides profile attribute that is used with <beans> tag as following.
<beans profile="prod">
   ------
</beans> 
The profile attribute is allowed only at <beans> tag level and not at <bean> tag level.
Now for the example we will create prod, dev and test profile as following.
1. XML Configuration for production environment.
spring-config-prod.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans profile="prod" 
  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="user" class="com.concretepage.User">
       <constructor-arg type="java.lang.Integer" value="100"/> 
       <constructor-arg type="java.lang.String" value="Prod User"/>
    </bean>
</beans> 
2. XML Configuration for development environment.
spring-config-dev.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans profile="dev" 
  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="user" class="com.concretepage.User">
       <constructor-arg type="java.lang.Integer" value="200"/> 
       <constructor-arg type="java.lang.String" value="Dev User"/>
    </bean>
</beans> 
3. XML Configuration for testing environment.
spring-config-test.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans profile="test" 
  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="user" class="com.concretepage.User">
       <constructor-arg type="java.lang.Integer" value="300"/> 
       <constructor-arg type="java.lang.String" value="Test User"/>
    </bean>
</beans> 
Now we will activate profile programmatically. First we will activate prod then dev and then test profile.
SpringProfileDemo.java
public class SpringProfileDemo {
  public static void main(String[] args) {
	ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config-*.xml");
	// Production environment
	ctx.getEnvironment().setActiveProfiles("prod");
	ctx.refresh();
	User user = (User) ctx.getBean("user");
	System.out.println("id:" + user.id + ", Name:" + user.name);

	// Development environment.
	ctx.getEnvironment().setActiveProfiles("dev");
	ctx.refresh();
	user = (User) ctx.getBean("user");
	System.out.println("id:" + user.id + ", Name:" + user.name);

	// Testing environment profile
	ctx.getEnvironment().setActiveProfiles("test");
	ctx.refresh();
	user = (User) ctx.getBean("user");
	System.out.println("id:" + user.id + ", Name:" + user.name);
  }
} 
Output
id:100, Name:Prod User
id:200, Name:Dev User
id:300, Name:Test User 

3. @Profile with @Component

@Profile can be used with stereotype annotations such as @Component, @Service, @Repository and @Controller. Find the sample example.
Animal.java
public interface Animal {
    String getMessage();
} 
DomesticAnimal.java
@Component
@Profile({"cow", "buffalo", "goat"})
public class DomesticAnimal implements Animal {
  @Override
  public String getMessage() {
     return "Hello Domestic Animal!";
  }
} 
DomesticAnimal will be registered if any of the cow, buffalo, goat profiles will be activated. Now find other class.
Lion.java
@Component
@Profile("lion")
public class Lion implements Animal {
   @Override
   public String getMessage() {
	return "Hello Lion!";
   }
} 
Lion will be registered if lion profile will be activated.
AppConfig.java
@Configuration
public class AppConfig {
} 
SpringProfileDemo.java
public class SpringProfileDemo {
 public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.getEnvironment().setActiveProfiles("goat");
    ctx.scan("com.concretepage");
    ctx.refresh();
    Animal animal = ctx.getBean(Animal.class);
    System.out.println(animal.getMessage());
 }
} 
Output
Hello Domestic Animal! 

In addition to the above usability, @Profile can also be used to set context path and port differently for production and development environment as following.
DevCustomizer.java
@Component
@Profile("dev")
public class DevCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
   @Override
   public void customize(ConfigurableServletWebServerFactory factory) {
	factory.setContextPath("/spring-boot-dev");
	factory.setPort(8484);		
   }
} 
ProdCustomizer.java
@Component
@Profile("prod")
public class ProdCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
   @Override
   public void customize(ConfigurableServletWebServerFactory factory) {
	factory.setContextPath("/spring-boot-prod");
	factory.setPort(8585);	
   }
} 

4. @Profile with @Bean

@Profile annotation can be used with @Bean annotation at method level in JavaConfig. Find the sample example.
AppConfig.java
@Configuration
public class AppConfig {
  @Bean
  @Profile({"cow", "buffalo", "goat"})
  DomesticAnimal domesticAnimal() {
     return new DomesticAnimal();
  }
  @Bean
  @Profile("lion")
  Lion lion() {
     return new Lion();
  }
} 
Animal.java
public interface Animal {
    String getMessage();
} 
Lion.java
public class Lion implements Animal {
   @Override
   public String getMessage() {
	return "Hello Lion!";
   }
} 
DomesticAnimal.java
public class DomesticAnimal implements Animal {
   @Override
   public String getMessage() {
	return "Hello Domestic Animal!";
   }
} 
SpringProfileDemo.java
public class SpringProfileDemo {
  public static void main(String[] args) {
	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
	ctx.getEnvironment().setActiveProfiles("buffalo");
	ctx.scan("com.concretepage");
	ctx.refresh();
	Animal animal = ctx.getBean(Animal.class);
	System.out.println(animal.getMessage());
  }
}
Output
Hello Domestic Animal! 

5. Define Profiles

We can define one or more than one profiles for a component annotated with @Component or JavaConfig annotated with @Configuration or using profile attribute with <beans> tag in XML configuration.
Case-1: Define single profile.
@Configuration
@Profile("prod")
public class ProdEnvConfig {
  ------
} 
For XML
<beans profile="prod" > 
The above config file will be registered if prod is activated such as
ctx.getEnvironment().setActiveProfiles("prod"); 
Case-2: Define more than one profile.
@Configuration
@Profile({"dev", "test"})
public class DevEnvConfig {
  ------
} 
For XML
<beans profile="dev, test" > 
The above config file will be registered either dev or test or both profiles are activated such as
ctx.getEnvironment().setActiveProfiles("dev"); 
or
ctx.getEnvironment().setActiveProfiles("test"); 
or
ctx.getEnvironment().setActiveProfiles("dev", "test"); 
Case-3: Use (!) with profile.
@Configuration
@Profile({"dev", "!prod"})
public class DevEnvConfig {
  ------
} 
For XML
<beans profile="dev, !prod" > 
The above config file will be registered if either dev or any other profile except prod such as test is activated.

6. Profile Expression

A profile string may contain a simple profile name or profile expression. A simple profile name is used as @Profile("prod") or @Profile({"dev", "test"}). A profile expression is created using logical not (!), logical and (&), and logical or (|) operators with only @Profile annotation and not with <beans> tag. Profile expression has been supported since Spring 5.1 version.
For the example suppose we have three profiles such as i.e. eligible, free and busy, then sample profile expressions will be as following.
Ex.1:
@Profile("!eligible & busy") 
The component will be registered only if eligible profile is not activated and busy profile is activated.
Ex.2:
@Profile("!busy | (eligible & free)") 
The component will be registered only if busy profile is not activated or eligible and free both profiles are activated.
Ex.3:
@Profile("(eligible & busy) | !free") 
The component will be registered only if eligible and busy both profiles are activated or free profile is not activated.
Find the sample complete example.
HomeConfig.java
@Configuration
@Profile("eligible & free")
public class HomeConfig {
  @Bean
  public Work getWork(){
    return new Work("Staying at home.");
  }
} 
JobConfig.java
@Configuration
@Profile("eligible & busy")
public class JobConfig {
   @Bean
   public Work getWork(){
	return new Work("Doing my job.");
   }
} 
SchoolConfig.java
@Configuration
@Profile("!eligible")
public class SchoolConfig {
   @Bean
   public Work getWork(){
	return new Work("Studying in my school.");
   }
} 
Work.java
package com.concretepage;
public class Work {
    public String desc;
    public Work(String desc){
       this.desc = desc;
    }
} 
SpringProfileDemo.java
public class SpringProfileDemo {
 public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.getEnvironment().setActiveProfiles("eligible", "busy");
    ctx.scan("com.concretepage.config");		
    ctx.refresh();
    Work ob = ctx.getBean(Work.class);
    System.out.println(ob.desc);
 }
} 
Output
Doing my job. 
For the line
ctx.getEnvironment().setActiveProfiles("eligible", "free"); 
Output
Staying at home. 
For the line
ctx.getEnvironment().setActiveProfiles("busy"); 
Output
Studying in my school. 

Note: We need to take care that & and | operators should be mixed only by using parenthesis, for example p1 & p2 | p3 is not valid expression, we should write it as (p1 & p2) | p3 or p1 & (p2 | p3).

7. Set Active Profiles Programmatically

To set active profiles programmatically, Spring provides ConfigurableEnvironment. It has following methods to manage profiles.
setActiveProfiles: Sets one or more active profiles.
addActiveProfile: Adds active profiles to the current set of active profiles.
setDefaultProfiles: Sets the default active profiles. Default active profiles are made active if no other profiles explicitly made active.
Find the sample example.
public class SpringProfileDemo {
  public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.getEnvironment().setActiveProfiles("eligible", "busy");
    ctx.scan("com.concretepage.config");
  }
} 
ctx.getEnvironment() returns instance of ConfigurableEnvironment. The profiles eligible and busy will be active.

8. Set Active Profiles as JVM System Property using Command Line

We can set active profiles using -Dspring.profiles.active argument with java command. In this case active profile configured in property file will be replaced by active profiles passed in command line. Suppose we want to enable prod and lion profiles.
java -jar -Dspring.profiles.active="prod, lion" target\spring-app.jar 
Find the print screen.
Spring Profiles
For single profile, we can use command as follows.
java -jar -Dspring.profiles.active=prod spring-app.jar 

9. Set Active Profiles using web.xml

We can set active profiles by configuring spring.profiles.active property using <context-param> in web.xml file in Spring web application. Suppose we want to set active dev profile. We will configure it in web.xml as following.
<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev</param-value>
</context-param> 
We can also set active more than one profile using <context-param>. Suppose we want to set active dev and buffalo profiles. We will configure it in web.xml as following.
<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev, buffalo</param-value>
</context-param> 
Find the complete web.xml file.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
   http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">

	<display-name>Spring Demo Project</display-name>
	<context-param>
	    <param-name>contextConfigLocation</param-name>
	    <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>		    
	</context-param>	
	<context-param>
	    <param-name>spring.profiles.active</param-name>
	    <param-value>dev, buffalo</param-value>
	</context-param>	
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>
		    org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app>  

10. Set Active Profiles using WebApplicationInitializer

We can set active profiles by configuring spring.profiles.active with WebApplicationInitializer in Spring web application as following.
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    super.onStartup(servletContext);
    servletContext.setInitParameter("spring.profiles.active", "dev");
} 
We can also set more than one active profile. Suppose we want to set active dev and buffalo profiles. We will configure it as following.
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    super.onStartup(servletContext);
    servletContext.setInitParameter("spring.profiles.active", "dev, buffalo");
} 
Find the complete code.
WebAppInitializer.java
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer  {
    @Override
    protected Class<?>[] getRootConfigClasses() {
	return new Class[] { AppConfig.class };
    }
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }
    @Override
    protected String[] getServletMappings() {
        return new String[]{ "/" };
    } 
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        servletContext.setInitParameter("spring.profiles.active", "dev, buffalo");
    }    
} 

11. Set Active Profiles using Maven

To set active profiles using Maven, we can use following ways.
1. Using command line with -Dspring-boot.run.profiles as following.
mvn spring-boot:run -Dspring-boot.run.profiles=dev,lion 
Find the print screen.
Spring Profiles
The profiles dev and lion has been activated. Comma is used to separate profiles when more than one profile need to be activated.
2. Configure <profiles> in pom.xml file.
<build>
  <plugins>
    <plugin>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-maven-plugin</artifactId>
	<configuration>
	  <profiles>
	    <profile>dev</profile>
	    <profile>lion</profile>
	  </profiles>
	</configuration>
    </plugin>
  </plugins>
</build> 
The profiles dev and lion will be activated when we start application using mvn spring-boot:run command.

12. Reference

Spring Doc: @Profile

13. Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us