Spring Profiles
1 CommentLast Updated on September 12, 2019 by jt
Enterprise Spring applications typically need to run in multiple environments. For example, development, testing, staging, and production. Each such environment has its own set of settings. For example, you might be using an embedded H2 database for development but an enterprise-grade Oracle or MySQL database for production. So the data source and connection configurations for them will differ when you run the application during development vs during production.
Spring applications typically have a large set of such configurations that vary across environments. In such scenarios, you can use Spring profiles. Spring profiles provide a way to segregate parts of your application configuration and make it be available only in certain environments.
In this post, we will learn how to use Spring profile.
Creating Profiles
Spring Boot by default comes with a property file, named application.properties
. To segregate the configuration based on the environments, we will create multiple property files. One for each environment we are targeting.
We will create three property files for the dev, test, and prod environments. Note the naming convention.
application-dev.properties
application-test.properties
application-prod.properties
The application.properties
file will be the master of all properties. Here we will specify which profile is active by using the property spring.profiles.active
.
The property files are as follows:
This is the application.properties
file.
spring.application.name = Spring Profiles spring.profiles.active = test app.message = This is the Primary Application Property
In the preceding code, the spring.profiles.active
property tells Spring which profile to use. Here we have set the test
profile as active.
In test, we will be using MySQL database.
The application-test.properties
file is this.
app.message = This is the TEST Environment property file spring.datasource.url=jdbc:mysql://localhost:3306/testDB spring.datasource.username=root spring.datasource.password=root123 spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
In dev, we will be using H2, an in-memory database. The application-dev.properties
file is this.
app.message = This is the DEV Environment Property file spring.h2.console.enabled=true spring.h2.console.path=/h2 spring.datasource.driverClassName=org.h2.Driver spring.datasource.url=jdbc:h2:mem:db spring.datasource.userName=sa spring.datasource.password=sa
The application-prod.properties
file is this.
app.message = This is the PRODUCTION Environment property file spring.datasource.url=jdbc:mysql://localhost:3306/prodDB spring.datasource.userName=root spring.datasource.password=root123 spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
Binding Externalized Configurations to Structured Objects
We have externalized configurations for different profiles to properties files. Now, we need to bind those configurations to objects of our application.
Spring provides the @ConfigurationProperties
annotation to bind and validate some external configurations defined in .properties file.
You can do it in two ways. Add the @ConfigurationProperties
annotation to a class definition.
Alternative, you can add it to a @Bean
method in a @Configuration
class.
Let us create DBConfiguration
class annotated with @ConfigurationProperties
to represent our external configuration.
package guru.springframework.config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @ConfigurationProperties("spring.datasource") public class DBConfiguration { private String driverClassName; private String url; private String userName; private String password; public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
The DBConfiguration
class above is marked with the @ConfigurationProperties("spring.datasource")
annotation. Here spring.datasource
represents configuration properties defined in the external configuration files.
The DBConfiguration
class contains the driverClassName
, url
, userName
, and password
properties along with the getter and setter methods. Each of these fields represent properties defined in the properties file.
Next, we need to register the preceding DBConfiguration
class using the @EnableConfigurationProperties
annotation.
package guru.springframework.config; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @Configuration @EnableConfigurationProperties(DBConfiguration.class) public class DBConnectionConfiguration { private DBConfiguration dbConfiguration; public DBConnectionConfiguration(DBConfiguration dbConfiguration) { this.dbConfiguration = dbConfiguration; } @Profile("dev") @Bean public String devDBCcnnection() { System.out.println("DB Connection for Dev"); System.out.println(dbConfiguration.getUrl()); System.out.println(dbConfiguration.getUserName()); System.out.println(dbConfiguration.getPassword()); System.out.println(dbConfiguration.getDriverClassName()); return "DB Connection for Dev"; } @Profile("test") @Bean public String devTestCcnnection() { System.out.println("DB Connection for Test"); System.out.println(dbConfiguration.getUrl()); System.out.println(dbConfiguration.getUserName()); System.out.println(dbConfiguration.getPassword()); System.out.println(dbConfiguration.getDriverClassName()); return "DB Connection for Test"; } @Profile("prod") @Bean public String devProdCcnnection() { System.out.println("DB Connection for Prod"); System.out.println(dbConfiguration.getUrl()); System.out.println(dbConfiguration.getUserName()); System.out.println(dbConfiguration.getPassword()); System.out.println(dbConfiguration.getDriverClassName()); return "DB Connection for Prod"; } }
In the preceding code, we have created a configuration class DBConnectionConfiguration
marked with the @Configuration
annotation. The @EnableConfigurationProperties(DBConfiguration.class)
annotation registers the @ConfigurationProperties
bean, DBConfiguration
in this configuration class.
For the purpose of demonstration, we have created three beans that prints the database configurations. We used the @Profile
annotation on each bean for the dev
, test
, and prod
profiles.
The code for the main class is this.
package guru.springframework; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; @SpringBootApplication @EnableConfigurationProperties public class SpringProfilesDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringProfilesDemoApplication.class, args); } }
The output on running the main class will be this.
DB Connection for Test jdbc:mysql://localhost:3306/testDB root root123 com.mysql.cj.jdbc.Driver
As we can see, the applications prints out the properties of the test environment as the active profile is set to test
.
Change the active profile to dev
in the application.properties
and run the application again. The output is this.
DB Connection for Dev jdbc:h2:mem:db sa sa org.h2.Driver
Summary
In this post, we saw how to use environment-specific properties files using Spring profiles. We can also mark any @Component
or @Configuration
class with @Profile
to limit when it is loaded. I am leaving this for another post.
Another way to set the active profile is by using the command line switch --spring.profiles.active
.
The spring.profiles.active
property follows the same ordering rules as other properties. This means you can replace the active profile in application.properties
by using the command line switch.
Sometimes, we might want to add profile-specific properties to the active profiles rather than replace them. To add active profiles, use the spring.profiles.include
property.
The source code for this post can be found here on GitHub.
stormraptor
Why would you even create a separate database profile for test and property file for test?
You can just put @AutoConfigureTestDatabase above your test class…..