04 Custom Configuration How to Create and Manage Custom Configuration Information

04 Custom Configuration - How to Create and Manage Custom Configuration Information #

In Lesson 03, we introduced the configuration system in Spring Boot, explained the organization structure of configuration files, and demonstrated how to dynamically load configuration information through code. Today, we will build on Lesson 03 and provide more advanced techniques related to the configuration system, as well as how to create and manage various types of custom configuration information.

How to Embed System Configuration Information in the Application? #

We know that Spring Boot provides many default configuration information through the auto-configuration mechanism. Some of these system configuration information can be used as configuration properties in our application.

For example, if we want to retrieve and manage the name of the current application as a configuration property, it’s as simple as using the ${spring.application.name} placeholder, as shown below:

myapplication.name : ${spring.application.name}

Similarly, we can reference other configuration properties from the configuration file using the ${} placeholder. In the following example, the value of the “system.description” property will be “The system springcss is used for health”.

system.name=springcss
system.domain=health
system.description=The system ${name} is used for ${domain}.

Let’s look at another scenario. Suppose we are using Maven to build our application. We can dynamically retrieve system-related information during the build process using the following configuration:

info:
  app:
    encoding: @project.build.sourceEncoding@
    java:
      source: @java.version@
      target: @java.version@

The above configuration has the same effect as the following static configuration:

info:
  app:
    encoding: UTF-8
    java:
      source: 1.8.0_31
      target: 1.8.0_31

Embedding system configuration information in the application can be very useful depending on the requirements, especially in DevOps-oriented application scenarios.

How to Create and Use Custom Configuration Information? #

In real-world development scenarios, the built-in configuration information provided by Spring Boot may not fully satisfy the development needs. This is where developers need to create and manage various custom configuration information. For example, in an e-commerce application, we want to reward users with a certain amount of points for each completed order. For better extensibility, the number of points should be configurable. We can create a custom configuration property as follows:

springcss.order.point = 10

Here, we set the number of points for each order to 10. Now, how can our application retrieve the value of this configuration property? There are two common methods.

Using the @Value Annotation #

Using the @Value annotation to inject configuration property values is a traditional approach. For the custom configuration property mentioned earlier, we can create a SpringCssConfig class as follows:

@Component
public class SpringCssConfig {
    @Value("${springcss.order.point}")
    private int point;
}

In the SpringCssConfig class, we simply add the @Value annotation to the field and specify the name of the configuration property.

Using the @ConfigurationProperties Annotation #

A more modern approach compared to the @Value annotation is to use the @ConfigurationProperties annotation. When using this annotation, we usually specify a “prefix” attribute to indicate the prefix of the configuration properties, as shown below:

@Component
@ConfigurationProperties(prefix = "springcss.order")
public class SpringCsshConfig {
    private int point;
    // getter/setter omitted
}

Compared to the @Value annotation, which can only be used to specify a specific configuration property, @ConfigurationProperties can be used to batch extract configuration properties. By specifying the prefix, we can automatically inject all configuration properties under that prefix into the business code.

Let’s consider a more common and complex scenario. Suppose the number of points a user earns based on an order is not fixed, but varies for each order type. If we were to use YAML format, the configuration would look like this:

springcss:
  points:
    orderType[1]: 10
    orderType[2]: 20
    orderType[3]: 30

To load all these configuration properties into our business code, we can easily achieve that using the @ConfigurationProperties annotation. We can directly define a Map object in the SpringCssConfig class and use key-value pairs to store the configuration data, as shown below:

@Component
@ConfigurationProperties(prefix="springcss.points")
public class SpringCssConfig {
    private Map<String, Integer> orderType = new HashMap<>();
    // getter/setter omitted
}

Here, we use a HashMap to store the key-value pairs. Similarly, we can also automatically inject common data structures.

Adding Auto-completion for Custom Configuration Properties #

If you have used configuration files in Spring Boot and added some built-in configuration properties, you may have noticed that when you start typing a configuration property prefix, IDEs like IDEA or Eclipse will automatically display all the available configuration properties under that prefix for you to choose from. Here’s an example:

Auto-completion effect of configuration properties in an IDE

This auto-completion feature is very useful for managing custom configuration information. How can we achieve this? When we add a custom configuration property to the application.yml file, IDEs won’t recognize it and won’t provide auto-completion for it, as shown below:

IDE not recognizing a configuration property

When encountering this situation, we can ignore it as it does not affect the execution. But to enable auto-completion, we need to generate configuration metadata. Generating metadata is simple - just click on the “Create metadata for ‘springcss.order.point’” button provided by the IDE to create the metadata file named additional-spring-configuration-metadata.json. The content of this file would be as follows:

{
    "properties": [{
        "name": "springcss.order.point",
        "type": "java.lang.String",
        "description": "A description for 'springcss.order.point'"
    }]
}

Now, if we enter “springcss” in the application.properties file, the IDE will automatically prompt the complete configuration content, as shown below:

Drawing 2.png

Effect of IDE’s automatic prompting of the ‘springcss’ prefix

In addition, suppose we need to specify a default value for the springcss.order.point configuration item. This can be achieved by adding a “defaultValue” item to the metadata, as shown below:

{
    "properties": [{
        "name": "springcss.order.point",
        "type": "java.lang.String",
        "description": "'springcss.order.point' is userd for setting the point when dealing with an order.",
        "defaultValue": 10
    }]
}

At this time, when setting this configuration item in the IDE, the default value of 10 for this configuration item will be suggested, as shown below:

Drawing 3.png

Effect of IDE’s automatic prompting for the springcss prefix with default value

How to organize and integrate configuration information? #

In the previous lesson, we mentioned the concept of Profile, which can be regarded as an effective means of managing configuration information. Today, we will continue to introduce another method of organizing and integrating configuration information, which also relies on the @ConfigurationProperties annotation introduced earlier.

Using the @PropertySources annotation #

When using the @ConfigurationProperties annotation, we can use it together with the @PropertySource annotation to specify from which specific configuration file to get the configuration information. For example, in the following example, we use the @PropertySource annotation to specify that the configuration information used in the @ConfigurationProperties annotation is read from the application.properties configuration file in the current classpath.

@Component
@ConfigurationProperties(prefix = "springcss.order")
@PropertySource(value = "classpath:application.properties")
public class SpringCssConfig {

Since we can use the @PropertySource annotation to specify a reference address to a configuration file, it is obvious that multiple configuration files can be imported. In this case, we use the @PropertySources annotation, as shown below:

@PropertySources({
    @PropertySource("classpath:application.properties"),
    @PropertySource("classpath:redis.properties"),
    @PropertySource("classpath:mq.properties")
})
public class SpringCssConfig {

Here, we combine the configuration file paths specified in multiple @PropertySource annotations using the @PropertySources annotation. The SpringCssConfig class can reference all the configuration items in these configuration files simultaneously.

On the other hand, we can also change the default loading location of the configuration file by configuring spring.config.location, so as to load multiple configuration files at the same time. For example, the following execution script will load the application.properties file on the D drive when starting the customerservice-0.0.1-SNAPSHOT.jar, as well as all configuration files in the config directory located in the current classpath.

java -jar cust