Spring Boot Profiles

In this Spring boot tutorial, we will learn Spring profiles, @Profile annotation, profile-specific beans, property files and configurations, profile groups, and activating a particular profile in application startup.

A profile instructs Spring to configure only the ApplicationContext instance that was defined when the specified profile was active.

1. Spring Profiles

1.1. What is a Profile?

In general, a profile is a segregation between different runtime environments in which the Spring application can run. For example, an application can run locally, in a development or test environment as well as in production. It is not easy to replicate the same hardware and software setup in all the above deployment environments. So the expectation is to configure the application in such a way that it must behave correctly in all these environments.

Interestingly, a profile is not limited to only deployment environments. It can be any type of segregation. For example, an application can connect to MySQL database in one profile while it will connect to H2 database in another profile. So here we have database configuration-specific profiles. Similarly, profiles can be segregated on any basis.

So, in simple words, the purpose of spring profiles is to activate different beans in different environments at bootstrap time. Under the hood, a profile can control only two things:

  • which beans are loaded into the application context
  • which application properties are applied

1.2. What is Default Profile?

Before going further deep into the concept, it is crucial to understand that if we do not specify any profile explicitly, then the default profile is activated automatically.

When using the default profile, all such beans will be initialized that do not belong to any specific profile. All profile-specific beans will be skipped from initialization.

It is equivalent to using the @Profile("default") annotation on all beans that do not belong to any specific profile.

The name of the default profile can be tuned using the spring.profiles.default property, as shown in the following example. This will change the name of the default profile from default to local.

spring.profiles.default=local

2. @Profile Annotation

The @Profile annotation tells Spring that those beans in the file should be instantiated only when the specified profile is active. The profile is activated using the spring.profiles.active JVM argument or the property defined in application.properties file.

java -jar your-application.jar -Dspring.profiles.active=local

The context is created empty and configuration is added after the profile is set.

In test classes, we can use @ActiveProfiles annotation to enable the specified profiles.

2.1. Using @Profile

The @Profile is used inside one of the following annotated classes:

For example, if we have three profiles local, dev and prod then we can use the following three classes to define profile-specific beans.

@Profile("local")
@Configuration
public class LocalProfileConfiguration {

   @Bean
   public DataSource h2DataSource() {/*...*/}
}
@Profile("dev")
@Configuration
public class DevelopmentProfileConfiguration {

   @Bean
   public DataSource mySqlDataSource() {/*...*/}
}
@Profile("prod")
@Configuration
public class ProductionProfileConfiguration {

   @Bean
   public DataSource oracleDataSource() {/*...*/}
}

Similarly, we can apply the @Profile annotation with stereotype annotations as well.

Note that profile names can also be prefixed with a NOT operator. The !prod name configures the beans in all non-production environments.

@Profile("!prod")
@Configuration
public class NonProductionProfileConfiguration {

   @Bean
   public DataSource h2DataSource() {/*...*/}
}

2.2. Not a Best Practice

Though @Profile is an extremely useful and simple concept, still it has one significant disadvantage. It spreads the profile-specific configurations in the source code in multiple places. And it makes it difficult to keep track of profile-specific configurations over time.

Another problem is activating multiple profiles can result in duplicate beans and runtime exceptions. For example, suppose we have H2 DataSource bean definition in two different profiles inMemoryDataSource and local.

@Profile("inMemoryDataSource")
@Configuration
public class DevelopmentProfileConfiguration {

   @Bean
   public DataSource datasource() {/*...*/}
}
@Profile("local")
@Configuration
public class ProductionProfileConfiguration {

   @Bean
   public DataSource datasource() {/*...*/}
}

If we decide to activate both, inMemoryDataSource and local, profiles in runtime then there will be two beans of same type and it will result in a runtime error.

So, having a properly segregated configuration and beans is difficult but of utmost importance, if we decide to use the @Profile annotation. It is always better to use application.properties files as a central place for controlling the profile-specific configurations and properties.

3. Profile Specific Properties

3.1. Profile Specific Properties Files

Spring Boot allows grouping the configuration parameters for different environments into the different application.properties configuration files. Spring Boot will automatically pick up the right configuration file depending on the activated profile and load the configuration properties from that file.

Properties files have to be named in the format application-{profile}.properties. For example,

  • application.properties – contains properties applicable to all environments
  • application-local.properties – configure the application when local profile is activated
  • application-dev.properties – configure the application when dev profile is activated
  • application-prod.properties – configure the application when prod profile is activated

For example, if we have different databases in different environments then we can create separate properties files like the following example:

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=root
spring.datasource.password=password

3.2. Multiple Profiles in application.properties

It is also possible to specify all the profile-specific configurations in only the application.properties file using the spring.config.activate.on-profile property as the separator to indicate the profile.

application.name=My Application

#--- local profile ---#
spring.config.activate.on-profile=local
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=

#--- dev profile ---#
spring.config.activate.on-profile=dev
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=root
spring.datasource.password=password

Note that we can not use spring.profiles.active in profile-specific documents as well as along with spring.config.activate.on-profile property. The following is an invalid configuration.

# Valid usecase
spring.profiles.active=prod

# Invalid usecase
spring.config.activate.on-profile=prod
spring.profiles.active=dev

4. Profile Groups

Starting Spring Boot 2.4, we can define profile groups as well. A profile group allows us to group similar profiles together.

For example, if we have different profiles for production configurations such as prodJms, prodDatabase, prodJndi etc., and we want to activate all these profiles while deploying the application in the production. To do so we can group all these profiles under a single profile name.

spring.profiles.group.prod=prodJms,prodDatabase,prodJndi

With the above profile group definition, activating the prod profile will activate prodJms, prodDatabase and prodJndi as well.

5. Activating a Profile

The spring.profiles.active is a standard property that Spring Boot will pick up automatically to activate a profile. Pass the profile name to this property value to activate that profile.

If we want to activate multiple profiles then we can pass comma-separated names of those profiles.

We can set it in many places, for example, in application.properties file:

spring.profiles.active=dev

As JVM startup argument:

$ java -jar app.jar -Dspring.profiles.active=dev

As environment variable:

export spring_profiles_active=dev

While configuring WebApplicationInitializer:

@Configuration
public class CustomWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        servletContext.setInitParameter("spring.profiles.active", "dev");
    }
}

6. Conclusion

In this Spring boot tutorial, we learned about the profiles that help in segregating the configurations and properties specific to different deployment environments, but not limited to this.

We learned to create profile-specific configurations and beans. We learned to activate a specific profile in runtime and profile groups.

Happy Learning !!

Sourcecode on Github

Comments

Subscribe
Notify of
guest
1 Comment
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode