What is Externalized configuration and Spring Profiling in Spring Boot
In this tutorial we are going to learn about Externalized configuration or Spring Profiling in Spring Boot with an example.
Externalized Configuration
Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments. You can use properties files, YAML files, environment variables, and command-line arguments to externalize configuration. Property values can be injected directly into your beans by using the @Value annotation, accessed through Spring’s Environment abstraction, or be bound to structured objects through @ConfigurationProperties.
What Are Profiles?
Every enterprise application has many environments, like:
Dev | Test | Stage | Prod | UAT / Pre-Prod
Each environment requires a setting that is specific to them. For example, in DEV, we do not need to constantly check database consistency. Whereas in TEST and STAGE, we need to. These environments host specific configurations called Profiles.
How Do we Maintain Profiles?
This is simple — properties files! We make properties files for each environment and set the profile in the application accordingly, so it will pick the respective properties file. Don’t worry, we will see how to set it up.
Let’s start with setting up a Spring Boot application from the Spring Starter.
In this demo application, we will see how to configure different databases and port numbers at runtime based on the specific environment by their respective profiles.
As the DB connection and port number is better to be kept in a property file, it remains external to an application and can be changed. We will do so here. But, Spring Boot — by default — provides just one property file ( application.properties). So, how will we segregate the properties based on the environment?
The solution would be to create more property files and add the “profile” name as the suffix and configure Spring Boot to pick the appropriate properties based on the profile.
Then, we need to create three application.properties:
- application-dev.properties
- application-test.properties
- application-prod.properties
Of course, the application.properties will remain as a master properties file, but if we override any key in the profile-specific file, the latter will gain precedence.
I will now define DB configuration properties for in respective properties file and add code in DBConfiguration.class to pick the appropriate settings.
Here is the base application.properties:
spring.profiles.active=dev
spring.application.name=employeeservice
app.message=This is the primary Application Property for ${spring.application.name}
In DEV, we will use an different port number:
#DEV ENVIRONEMNT SETTING#
app.message= This is the property file for the ${spring.application.name} specific to DEV Environment
server.port=8082
spring.datasource.url=jdbc:mysql://localhost:3306/hclDEV
spring.datasource.username=root
spring.datasource.password=root123
spring.jpa.hibernate.ddl-auto=update
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
In TEST, we will be using a different port number.
#TEST ENVIRONEMNT SETTING#
app.message= This is the property file for the ${spring.application.name} specific to TEST Environment
server.port=8084
spring.datasource.url=jdbc:mysql://localhost:3306/hclTEST
spring.datasource.username=root
spring.datasource.password=root123
In PROD, we will be using a different port number.
#PROD ENVIRONEMNT SETTING#
app.message= This is the property file for the ${spring.application.name} specific to PRODUCTION Environment!! Be ALERT!!
server.port=8083
spring.datasource.url=jdbc:mysql://localhost:3306/hclPROD
spring.datasource.username=root
spring.datasource.password=root123
Now, we are done with properties files. Let’s configure in the DatabaseConfiguration.class to pick the correct one.
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
@ConfigurationProperties("spring.datasource")
public class DatabaseConfiguration {
private String url;
private String username;
private String password;
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;
}
@Profile("dev")
@Bean
public String devDatabaseConnection() {
System.out.println("DB connection to DEV");
System.out.println(url);
return "DB connection for DEV - H2";
}
@Profile("test")
@Bean
public String testDatabaseConnection() {
System.out.println("DB Connection to TEST");
System.out.println(url);
return "DB Connection to TEST";
}
@Profile("prod")
@Bean
public String prodDatabaseConnection() {
System.out.println("DB Connection to PROD");
System.out.println(url);
return "DB Connection to PROD";
}
}
We have used the @Profile(“Dev”) to let the system know that this is the BEAN that should be picked up when we set the application profile to DEV. The other two beans will not be created at all.
One last setting is how to let the system know that this is DEV, TEST, or PROD. But, how do we do this?
We will use the application.properties to use the key below:
spring.profiles.active=dev
From here, Spring Boot will know which profile to pick. Let’s run the application now!
With the profile in DEV mode, and it should on port number 8082.
Now, change the profile to PROD. and it will run on an different port number i.e., 8083.
That’s it! We just have to change it once at the application.properties to let Spring Boot know which environment the code is deployed in, and it will do the magic with the setting.