In Spring Framework, profiles are logical groups of bean definitions that are registered only if the given profile is active. It is possible to assign a bean with multiple Profiles, separated with logical operations like not (!
), and (&
) and or (|
) etc. Profiles in Spring are specified with the @Profile annotation in Spring.
It is possible to use and activate @Profile annotations in several ways, we will explore each of them in detail.
You only need the Spring-core and Spring-context dependencies to make this example work.
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> </dependencies>
Optionally you can specify the test dependencies
<dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.platform</groupId> <artifactId>junit-platform-runner</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <scope>test</scope> </dependency>
When to use Spring @Profile annotation
Before learning to use, let us understand why you need the annotation.
- Lets say you may want to load different set of configurations based on the environment. e.g. In memory datasource for Testing, MySql for Production. So you can load different dataSource beans based on the profile values.
- Another common example is to load different application.properties files based on the environemnt. e.g. application-dev.properties for dev, application-test.properties for test and so on.
There are several ways in which @Profile annotation can be used and several ways in which a specific profile can be activated.
1. Use @Profile with stereotypes on class level
Consider a use case when you have two dataSources, RestDataSource
and GraphQlDataSource
. You want to activate only one of them based on the profile
value.
You can see in the below code, the GraphQlDataSource
has the profile graphQl
. But the RestDataSource
has 2 profile values rest
and default
. The default profile is activated when no profile value is set in the application.
@Component @Profile("graphQl") public class GraphQlDataSource implements DataSource { @Override public String getName() { return "GraphQlDataSource"; } }
@Component @Profile({"rest", "default"}) //multiple profiles public class RestDataSource implements DataSource { //Logic to fetch data from API @Override public String getName() { return "RestDataSource"; } }
@Configuration @ComponentScan("com.jsbd.profiles") public class ProfilesConfig { }
public interface DataSource { public String getName(); }
There are different ways we can set the profile value to test the above code.
a. Use @ActiveProfiles in spring-test to set a profile
We can use the @ActiveProfiles
annotation in the JUnit test class to set a specific profile. Remember, this is only available in test classes. The below example demonstrates how to activate a specific profile. When you don’t mention any the default profile gets activated.
@SpringJUnitConfig(ProfilesConfig.class) @ActiveProfiles("rest") public class TestRestProfile { @Autowired private DataSource dataSource; @Test public void testDataSource(){ Assert.assertNotNull(dataSource); Assert.assertEquals(dataSource.getClass(), RestDataSource.class); System.out.println(dataSource.getClass()); } }
@SpringJUnitConfig(ProfilesConfig.class) @ActiveProfiles("graphQl") public class TestGraphQlProfile { @Autowired private DataSource dataSource; @Test public void testGraphQlProfile() { System.out.println(dataSource); Assert.assertNotNull(dataSource); Assert.assertEquals(dataSource.getClass(), GraphQlDataSource.class); } }
@SpringJUnitConfig(ProfilesConfig.class) public class TestDefaultProfile { @Autowired private DataSource dataSource; @Test public void testDefaultProfile() { Assert.assertNotNull(dataSource); Assert.assertEquals(dataSource.getClass(), RestDataSource.class); } }
b. Activate a profile using JVM parameter
You can also activate a specific profile in your application using the JVM parameter spring.profiles.active
as shown below.
$ java -jar -Dspring.profiles.active=graphQl target/spring-profile-app-1.0.jar
c. Set the profile value Programmatically
Programmatically you can set a specific profile using the Environment
API. You can either @Autowire
the Environment interface or obtain it from the ApplicationContext
.
public class ProfilesApp { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.getEnvironment().setActiveProfiles("graphQl"); context.register(ProfilesConfig.class); context.refresh(); DataSource dataSource = context.getBean(DataSource.class); System.out.println(dataSource.getClass()); } }
Alternatively, you can inject the profile value through ConfigurableEnvironment
property as shown below.
@Autowired private ConfigurableEnvironment env; ... env.setActiveProfiles("rest");
2. Use @Profile with @Configuration
Just like how you use @Profile with @Component, @Repository or @Service, it is also possible to specify the profiles for Configurations. The below example shows the use of profiles with @Configuration annotation.
@Configuration @Profile("production") public class ProdConnnectionPoolConfig { @Bean public ConnectionPoolDataSource prodConnectionPool() { //prod database connection pool } }
@Configuration @Profile("development") public class DevConnnectionPoolConfig { @Bean public ConnectionPoolDataSource devConnectionPool() { //dev database connection pool } }
3. Use @Profile with @Bean annotation
The @Profile annotation is also used with @Bean to dynamically activate the specific bean based on the profile value. You can see in the below example, a specific ConnectionPoolDataSource
is set based on profile.
@Configuration public class ConnnectionPoolConfig { @Bean @Profile("production") public ConnectionPoolDataSource prodConnectionPool() { //prod database connection pool } @Bean @Profile("development") public ConnectionPoolDataSource devConnectionPool() { //dev database connection pool } }
Conclusion:
There are also other mechanisms to set the profile value using Maven/Gradle build configurations, using external properties files, etc. I have only discussed the most used approaches in this article. This article only talks about Spring-core features, I will cover the Spring-boot capabilities in a separate article. I hope you have got a good understanding of profiles in Spring and when to use them. You can also download the code examples from GitHub.
Leave A Comment