Spring boot profiles
Profiles in spring boot enable defining different set of configurations for different environments, such as development, test, and production.
Suppose you have have different database configurations for each environment, or different logging settings.
One way to switch between these configurations is to change the values manually when running the application.
Another way is using spring profiles, which can be switched according to the environment, without any code changes required and we will see how to do that in this article.
With spring boot profiles, you can define beans specific to a profile. This means that a bean will only be loaded if it belongs to a particular profile and that profile is active.
To make a bean part of a profile, add @Profile
annotation with a string as shown below
@Component @Profile("dev") public class DevComponent { @Value("${env}") String environment; @PostConstruct public void log() { System.out.println(environment); } }
This means that this bean will only be loaded when dev profile is active.
You can say that profile is a way of grouping beans.
Let’s define another bean with qa profile.
@Component @Profile("qa") public class QAComponent { @Value("${env}") String environment; @PostConstruct public void log() { System.out.println(environment); } }
You can also associate a bean with more than one profiles by providing profile names in an array as shown below
@Component @Profile({"qa", "dev"}) public class QAComponent { @Value("${env}") String environment; @PostConstruct public void log() { System.out.println(environment); } }
Profile specific properties
With Spring profile, you can not only register beans specific to active profile, but also load properties that belong to active profile.
Convention to define properties file is application-<profileName>.properties
.
That is, we can create separate properties file for dev and qa profile as shown below.
# application-dev.properties env=In Dev environment
# application-qa.properties env=In QA environment
Now, if dev profile is active,
1. DevComponent
bean will be loaded.
2. application-dev.properties
will be loaded.
To activate a profile,
spring.profiles.active
property is used, with its value as the name of profile that should be active.Remember that you can activate more than one profiles at a time by providing the names of all the profiles separated by a comma.
There are multiple ways to set spring.profiles.active
property, which are covered next.
1. In application.properties file
You can define spring.profiles.active
property in application.properties
file of spring boot application as shown below
#application.properties server.port=8085 spring.profiles.active=qa
When you will start the application with this configuration, following message will be printed
In QA environment
which shows that application-qa.properties
file was loaded and QAComponent
bean was registered in spring application context.
2. Using system property
You can set spring.profiles.active
property using System.setProperty()
method.
It should be set before starting spring boot application so that it should know which profile needs to be loaded as shown below
System.setProperty("spring.profiles.active", "qa"); SpringApplication.run(DemoApplication.class, args);
3. While running jar
You can also provide active profile while running spring boot application jar at the command line as shown below
java -jar demo-application.jar --spring.profiles.active=qa
You can also set active profile from command line with -D
flag as below
java -Dspring.profiles.active=prod -jar demo-application.jar
4. In web.xml
If your application is a traditional web application that uses web.xml, then you can set the active profile as a context parameter as shown below
<context-param> <param-name>spring.profiles.active</param-name> <param-value>dev</param-value> </context-param>
Activate profile with SpringApplicationBuilder
There is another way to set active profile, using SpringApplicationBuilder
class.
This class is used to start a spring boot application and you can specify active profiles with its profiles()
method as below
new SpringApplicationBuilder(DemoApplication.class). profiles("dev"). run(args);
You can activate multiple profiles by providing their names separated by a comma in profiles()
method.
If you want to know, which profile is active at any moment, then there are multiple ways for that too.
1. Using spring.profiles.active property
This is the same property, which is used to set the active profile.
You can get its value to determine which profile is active as shown below
@Component public class Profiler { @Value("${spring.profiles.active}") String activeProfiles }
Here, the variable activeProfiles
will contain the name of profile.
If there are more than one profiles active, then they will be comma separated.
In the above example, if active profile has not been set, the @Value
will throw IllegalArgumentException
and the application will not start.
To prevent this, we need to initialize this property with a blank value, if it is not available as below
@Component public class Profiler { @Value("${spring.profiles.active:}") String activeProfiles }
2. Using environment
org.springframework.core.env.Environment
class has a getActiveProfiles()
method, which returns a string array containing the profiles, which are active for the current application.
It can be used as below
@Component public class Profiler { @Autowired Environment e; void printActiveProfiles() { for(String p : e.getActiveProfiles()) { // p contains active profile } } }
Default profile
When no profile is set, a default profile is active.
All the beans that do not have @Profile
annotation, belong to the default profile.
A default profile can be also be set using spring.profiles.default
property. This profile will be active, when no profile is set with spring.profiles.active
property.
It is different from spring’s default profile. spring.profiles.default=test
says that use test profile, when no other profile is active.
Logical operators in profiles
You can use following logical operators with @Profile
to load beans conditionally as per profiles.
1. ! operator
@Profile("!qa")
means that this bean will not be loaded if qa profile is active. Thus, it reverses the bean association with a profile.
2. && operator
@Profile("dev && qa")
means that this bean will be registered only when both qa and dev profiles are active.
Two profiles can be activated as
spring.profiles.active=dev,qa
Similarly, @Profile("dev && !qa")
means that this bean is loaded, when the at least dev profile is active and qa is not one of the active profiles.
3. || operator
@Profile("dev || qa")
means that a bean with annotation will be registered, when one of the active profiles is either dev or qa.
Most applications have different databases configured for various environments such as production, development and qa.
Instead of changing database parameters every time, use spring profiles for switching database connections by creating data sources separately corresponding to each environment. Example,
@Profile("dev") @Configuration public class DevDBConfig { @Value("${spring.datasource.url}") private String url; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Bean public DataSource dataSource() { return DataSourceBuilder .create() .url(url) .username(username) .password(password) .build(); } } @Profile("prod") @Configuration public class ProdDBConfig { @Value("${spring.datasource.url}") private String url; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Bean public DataSource dataSource() { return DataSourceBuilder .create() .url(url) .username(username) .password(password) .build(); } }
Create application-prod.properties
and application-dev.properties
file having above db connection properties.
Simply set active profile and a datasource corresponding to it.
Important notes
1. If their are common keys in application.properties
and application-profile.properties
, then profile specific values will overwrite the main property values.
2. If there are common keys in all the profiles and multiple profiles are loaded comma-separated, then the last property value will overwrite previous values.
3. Beans that do not have @Profile
annotation will be loaded with all profiles, even with a default profile.
4. Beans having @Profile
annotation, will be loaded only when the corresponding profile is active.
In conclusion, profiles in spring boot provide a powerful way to configure your application for different environments, and make it easy to switch between configurations.
Hope the article was useful.