03 Multi Dimensional Configuration How to Use the Configuration Hierarchy in Spring Boot

03 Multi-dimensional Configuration - How to Use the Configuration Hierarchy in Spring Boot #

The configuration system is the foundation of developing applications using the Spring Boot framework, and automatic configuration is one of its core features. Today, I will guide you on how to use the Spring Boot configuration system in a systematic way. Let’s start by creating and running our first web application.

Creating the First Spring Boot Web Application #

There are many ways to create a web application with Spring Boot, but the simplest and most direct method is to use the Spring Initializer template provided by the official Spring website.

To use the Spring Initializer, you can directly access the website http://start.spring.io/, select “Maven Project”, specify the Group and Artifact, and then select “Spring Web” in the dependencies. Click “Generate” to create the project. The following screenshot shows the interface:

Drawing 0.png

Creating a Web Application using Spring Initializer

Of course, for those who have some development experience, you can also use the features and structure of Maven itself to generate the code project shown in the screenshot.

Next, let’s add some RESTful endpoints to this project by following the basic method of creating a Controller mentioned in lecture 02. Here, we will create a CustomerController class as shown below:

@RestController
@RequestMapping(value="customers")
public class CustomerController {
    
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public CustomerTicket getCustomerTicketById(@PathVariable Long id) {        
        CustomerTicket customerTicket = new CustomerTicket();
        customerTicket.setId(1L);
        customerTicket.setAccountId(100L);
        customerTicket.setOrderNumber("Order00001");
        customerTicket.setDescription("DemoOrder");
        customerTicket.setCreateTime(new Date());
        
        return customerTicket;
    }
}

Please note that we have used hardcoding here to demonstrate the response handling of an HTTP GET request.

Now that the RESTful endpoints are developed, we need to package the application. With Spring Boot and Maven, when we use the mvn package command to build the entire application, it will generate a customerservice-0.0.1-SNAPSHOT.jar file, which is an executable file with an embedded Tomcat web server. That means we can run this Spring Boot application directly using the following command:

java -jar customerservice-0.0.1-SNAPSHOT.jar

So, how do we verify if the service has started successfully and if the HTTP requests receive the correct responses? In lecture 03, we introduced Postman to demonstrate how to access remote services through HTTP endpoints.

Postman provides a powerful web API and HTTP request debugging functionality, with a clean and intuitive interface that makes it easy and convenient to use. Postman can send any type of HTTP request (e.g., GET, HEAD, POST, PUT) and can include any number of parameters and HTTP request headers.

Now, let’s use Postman to access the endpoint “/customers/1” at “http://localhost:8083” as shown in the following screenshot. This will give us the HTTP response shown in the screenshot, indicating that the service has been successfully started.

Drawing 1.png

Great! Now we have learned how to build, package, and run a simple web application. This is the starting point for all development work. We will use this method to present all the sample code we will introduce, including the Spring Boot configuration system we are about to cover.

Configuration System in Spring Boot #

In Spring Boot, the core design principle is to use convention over configuration for managing configuration information. Under this principle, the number of configuration settings that developers need to set is greatly reduced compared to using the traditional Spring framework. Today, our main focus is on understanding and using the configuration organization in Spring Boot, which brings us to a key concept: Profile.

Configuration Files and Profiles #

Profiles essentially represent a dimension for organizing configuration information, and they can have different meanings in different scenarios. For example, if a profile represents a state, we can use values like “open”, “halfopen”, and “close” to represent fully open, partially open, and closed states, respectively. Another example is when a system needs to define a series of templates, with each template containing a set of configuration items. In this case, we can create profiles for these templates. The definitions of these states or templates are completely designed by the developers, so we can customize various profiles according to our needs. This is the basic concept of profiles.

On the other hand, to achieve centralized management, Spring Boot has established certain conventions for naming configuration files, using the concepts of labels and profiles to specify the versioning information and runtime environment of the configuration information. In Spring Boot, configuration files support both .properties and .yml formats. The following are commonly used and valid naming conventions for configuration files:

/{application}.yml
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

YAML syntax is similar to other high-level languages and can express various data structures such as lists, maps, and scalars in an intuitive way. It is particularly suitable for representing or editing data structures and various configuration files. Here, we specify the following data source configuration using a .yml file, as shown below:

spring: 
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/account
    username: root
    password: root

If you use a .properties configuration file, the above configuration information will be represented as follows:

spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/account
spring.datasource.username=root 
spring.datasource.password=root

Clearly, configurations like this usually have many sets of configurations depending on the different environments. Suppose we have the following collection of configuration files:

Drawing 2.png

Illustration of Multiple Configuration Files

Note that there is a global application.yml configuration file and multiple local profile configuration files. So, how do we specify which set of configurations to use? In Spring Boot, we can use the following configuration method in the main application.properties file to activate the currently used profile:

spring.profiles.active = test

The above configuration means that the system will read the configurations from the application-test.yml file. Similarly, if using a .yml file, you can use the following configuration method:

spring:
  profiles:
    active: test

In fact, we can activate multiple profiles at the same time, depending on the requirements and dimensions of the system configuration.

spring.profiles.active: prod, myprofile1, myprofile2

Of course, if you want to keep all the profile configuration information in one file instead of scattered in multiple files, Spring Boot also supports it. The only thing you need to do is to organize and segment this information according to profiles, as shown below:

spring:
  profiles: test
  # test environment related configuration information

spring:
  profiles: prod
  # prod environment related configuration information

Although the above method is effective, in Lesson 03, it is still recommended to manage profile configuration information using the method of organizing multiple configuration files, so as not to be confused and prone to errors.

Finally, if we don’t want to specify the active profile in the global configuration file, but want to delay this process until the service is running, we can directly add the “–spring.profiles.active” parameter to the “java -jar” command as shown below:

java -jar customerservice-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod

This implementation is very useful in scenarios where automated packaging and deployment are performed using scripts.

Code Control and Profiles #

In Spring Boot, the application scenarios of profile concept also include dynamically controlling the code execution flow. For this purpose, we need to use the @Profile annotation. Let’s start with a simple example:

@Configuration
public class DataSourceConfig {

    @Bean
    @Profile("dev")
    public DataSource devDataSource() {
        // create DataSource for dev environment
    }
    
    @Bean
    @Profile("prod")
    public DataSource prodDataSource(){
        // create DataSource for prod environment
    }
}

As you can see, we have built a DataSourceConfig configuration class specifically to manage the DataSources required by various environments. It is worth noting that we use the @Profile annotation to specify the specific DataSource creation code that needs to be executed. In this way, the same effect as using configuration files can be achieved.

Furthermore, being able to control the creation process of JavaBeans in code provides greater possibilities for dynamically executing code flow based on various conditions. For example, in the daily development process, a common requirement is to initialize data based on different runtime environments. The common approach is to execute a piece of code or script independently. Based on the @Profile annotation, we can include this process in the code and automate it, as shown below:

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

    @Bean
    public CommandLineRunner dataInit() { 
        return new CommandLineRunner() {
            @Override
            public void run(String... args) throws Exception {
                // execute data initialization for Dev environment
            }
        };  
    }
}

Here, we used the startup task interface CommandLineRunner provided by Spring Boot. The code that implements this interface will be automatically executed when the Spring Boot application starts. We will see the specific usage of this interface in subsequent courses.

The @Profile annotation has a wide range of applications. We can add it to classes and methods that include the @Configuration and @Component annotations. In other words, it can be extended to various annotations that inherit the @Component annotation, such as @Service, @Controller, and @Repository.

Common Configuration Scenarios and Contents #

At the end of today’s lesson, we provide several common configuration examples to help you further understand the configuration system in Spring Boot.

For a web application, the most common configuration may be specifying the port address that the service is exposed on, as shown below:

server:
  port: 8080

At the same time, accessing the database is also a basic function of a web application. Therefore, setting up the data source is another common configuration scenario. We provided a basic example when creating the first Spring Boot web application in Lesson 02. Here, let’s take JPA as an example and provide the following configuration solution:

spring:
  jpa:
    hibernate:
      ddl-auto: create
    show-sql: true

Obviously, this uses Hibernate as the implementation framework for the JPA specification, and sets related properties such as show-sql. Then, developers often need to set the log level and object. The following is a typical configuration example:

logging.level.root=WARN
logging.level.com.springcss.customer=INFO

We set the global log level of the system to WARN, while adjusting the log level of the custom com.springcss.customer package to INFO.

As the content of this course unfolds, these common configuration information will be displayed in our SpringCSS case analysis. It is important to note that Spring Boot has automatically built-in many default configurations based on the application.properties or application.yml global configuration file. Even if we do not set the above configuration content, Spring Boot can still complete the system initialization based on these default configurations. Auto-configuration is a core concept in Spring Boot, and we will provide a detailed analysis of its implementation principles in subsequent content.

Summary and Preview #

The configuration system is the foundation of learning Spring Boot applications. In today’s lesson, we systematically reviewed the profile concept in Spring Boot and how to use this core concept through configuration files and code control.