How to Use Spring's @Profile Annotation for Flexible Configurations

The @Profile annotation in Spring allows you to segregate configurations to be available only in specific environments. If you mark a @Component (and its specializations) or any @Configuration or @Bean with the @Profile annotation, it will make them available only if the profile specified is active. You can set the profile using application.properties by using the spring.profiles.active property, or by specifying it in the command line when running the application. You can also use the spring.profiles.include property to add and combine more configuration profiles. Let’s explore some examples. Using profiles to separate environments In your application, you may have a database connection, but you need to deal with new features and test them in a separate environment. You need a validation environment before shipping your new feature to production. We can call this environment dev. And for the stable things that are running for all users of your application, you have a prod environment. Each environment has its own database. You can use profiles to set up your application pointing to the right environment. In this case, it will point to the right data source for the environment, but you can separate many other things if needed. So you can have a bean data source for the dev profile that is pointing to the dev database: import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSource; @Configuration @Profile("dev") public class DevDataSourceConfig { @Bean public DataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setUrl("jdbc:h2:mem:devdb"); dataSource.setUsername("devuser"); dataSource.setPassword("devpass"); return dataSource; } } And another bean configuration for the prod profile is pointing to the production data source: import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSource; @Configuration @Profile("prod") public class ProdDataSourceConfig { @Bean public DataSource dataSource() { BasicDataSource dataSource = new BasicDataSource(); dataSource.setUrl("jdbc:mysql://prodserver:3306/proddb"); dataSource.setUsername("produser"); dataSource.setPassword("prodpass"); return dataSource; } } (In the above code, I created a dummy class called BasicDataSource, which implements DataSource just to exemplify.) When you run your application without setting a profile, this log will be shown, telling that Spring is using the default profile: 2024-07-17T21:50:05.329-03:00 INFO 18568 --- [ main] com.spring.mastery.MasteryApplication : No active profile set, falling back to 1 default profile: "default" You can set the profile in the application.properties like this: spring.profiles.active=dev This log will show up: 2024-07-17T21:52:03.996-03:00 INFO 8240 --- [ main] com.spring.mastery.MasteryApplication : The following 1 profile is active: "dev" Spring will load the data source connection to the dev environment. You can set the profile in the command line: Using VM arguments: java -jar -Dspring.profiles.active=prod application.jar Or you can use program arguments: java -jar application.jar --spring.profiles.active=prod Now, when running your application, you choose the profile that the scenario needs. Combining Profiles Another interesting thing you could do is combine two different profiles. Let’s suppose that you have to do a test, and in this test, you want to load up the real cache manager bean that is used by your application and combine it with the test database. In this case, we are going to call the profile that holds the cache manager as common and the test profile that has the data source configuration for the test database. In your properties, you can set up the active environment as a test, and include the other profiles that you need. Like this in application.properties: spring.profiles.active=test spring.profiles.include=common So your Cache Manager is configured as the Common Profile: 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("common") public class CommonConfig { @Bean public CacheManager cacheManager() { log.info("Loading cache manager from common profile"); return new Concurre

Apr 15, 2025 - 17:12
 0
How to Use Spring's @Profile Annotation for Flexible Configurations

The @Profile annotation in Spring allows you to segregate configurations to be available only in specific environments.

If you mark a @Component (and its specializations) or any @Configuration or @Bean with the @Profile annotation, it will make them available only if the profile specified is active.

You can set the profile using application.properties by using the spring.profiles.active property, or by specifying it in the command line when running the application.

You can also use the spring.profiles.include property to add and combine more configuration profiles.

Let’s explore some examples.

Using profiles to separate environments

In your application, you may have a database connection, but you need to deal with new features and test them in a separate environment. You need a validation environment before shipping your new feature to production. We can call this environment dev.

And for the stable things that are running for all users of your application, you have a prod environment.

Each environment has its own database. You can use profiles to set up your application pointing to the right environment. In this case, it will point to the right data source for the environment, but you can separate many other things if needed.

So you can have a bean data source for the dev profile that is pointing to the dev database:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;

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

    @Bean
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl("jdbc:h2:mem:devdb");
        dataSource.setUsername("devuser");
        dataSource.setPassword("devpass");
        return dataSource;
    }
}

And another bean configuration for the prod profile is pointing to the production data source:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;

@Configuration
@Profile("prod")
public class ProdDataSourceConfig {

    @Bean
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl("jdbc:mysql://prodserver:3306/proddb");
        dataSource.setUsername("produser");
        dataSource.setPassword("prodpass");
        return dataSource;
    }
}

(In the above code, I created a dummy class called BasicDataSource, which implements DataSource just to exemplify.)

When you run your application without setting a profile, this log will be shown, telling that Spring is using the default profile:

2024-07-17T21:50:05.329-03:00  INFO 18568 --- [           main] com.spring.mastery.MasteryApplication    : No active profile set, falling back to 1 default profile: "default"

You can set the profile in the application.properties like this:

spring.profiles.active=dev

This log will show up:

2024-07-17T21:52:03.996-03:00  INFO 8240 --- [           main] com.spring.mastery.MasteryApplication    : The following 1 profile is active: "dev"

Spring will load the data source connection to the dev environment.

You can set the profile in the command line:

Using VM arguments:

java -jar -Dspring.profiles.active=prod application.jar

Or you can use program arguments:

java -jar application.jar --spring.profiles.active=prod

Now, when running your application, you choose the profile that the scenario needs.

Combining Profiles

Another interesting thing you could do is combine two different profiles.

Let’s suppose that you have to do a test, and in this test, you want to load up the real cache manager bean that is used by your application and combine it with the test database.

In this case, we are going to call the profile that holds the cache manager as common and the test profile that has the data source configuration for the test database.

In your properties, you can set up the active environment as a test, and include the other profiles that you need.

Like this in application.properties:

spring.profiles.active=test
spring.profiles.include=common

So your Cache Manager is configured as the Common Profile:

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("common")
public class CommonConfig {

    @Bean
    public CacheManager cacheManager() {
        log.info("Loading cache manager from common profile");
        return new ConcurrentMapCacheManager("entities");
    }
}

Your Test Profile points to the test data source:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;

@Configuration
@Profile("test")
public class TestDataSourceConfig {

    @Bean
    public DataSource dataSource() {
        log.info("Loading data source bean from the test profile");
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl("jdbc:h2:mem:testdb");
        dataSource.setUsername("testuser");
        dataSource.setPassword("testpass");
        return dataSource;
    }
}

When you run your application, you will have the beans from both profiles available and set.

A log line like this will show up:

The following 2 profiles are active: "common", "test"

In this blog post, we did this only with @Bean and @Configuration classes, but you could use this for all @Component and specializations too!

When used in a @Configuration class, it will set all the @Beans in it to the specific profile.

Now you’ve learned how to use the @Profile annotation in your project. Have you seen this annotation before? Can you think of more usages for this annotation? Share your thoughts with me in the comments or on social media.

If you like this topic, make sure to follow me. In the following days, I’ll be explaining more about Spring annotations! Stay tuned!

Willian Moya (@WillianFMoya) / X (twitter.com)

Willian Ferreira Moya | LinkedIn