Skip to content
JackSparrow414
Go back

Custom YAML Configuration in Spring Boot

Table of contents

Open Table of contents

Custom YAML Configuration in Spring Boot

Introduction

When using Spring Boot or third-party JARs, configuration in a YAML file is straightforward. How can we implement our own YAML configuration?

Implementation

Add POM Dependencies

   <!--Dependency required for custom YAML configuration-->
   <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
		</dependency>
     <!--Use Lombok; note that Lombok is optional here.-->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>

Create a JSON Metadata File

The file contents are:

{
  "groups": [
    {
      "name": "jack.sparrow",
      "type": "com.learn.spring.spring01.config.CustomConfigurationProperties",
      "sourceType": "com.learn.spring.spring01.config.CustomConfigurationProperties"
    }
  ],
  "properties": [
    {
      "name": "jack.sparrow.enabled",
      "type": "java.lang.Boolean",
      "defaultValue": true,
      "description": "Whether the configuration is enabled"
    },
    {
      "name": "jack.sparrow.code",
      "type": "java.lang.Integer",
      "sourceType": "com.learn.spring.spring01.config.CustomConfigurationProperties",
      "description": "The code property of the configuration properties class",
      "defaultValue": 1
    },
    {
      "name": "jack.sparrow.name",
      "type": "java.lang.String",
      "sourceType": "com.learn.spring.spring01.config.CustomConfigurationProperties"
    },
    {
      "name": "jack.sparrow.check",
      "type": "java.lang.Boolean",
      "sourceType": "com.learn.spring.spring01.config.CustomConfigurationProperties",
      "description": "The check property",
      "defaultValue": true
    },
    {
      "name": "jack.sparrow.name.nameMap",
      "type": "java.util.Map<java.lang.String,java.lang.String>",
      "sourceType": "com.learn.spring.spring01.config.CustomConfigurationComplexProperties",
      "description": "The map property"
    }
  ]
}

groups: these entries represent the parent nodes of the custom configuration. Define one group for each parent node.

A group’s name is the parent node’s name in the YAML configuration.

A group’s type and sourceType are the same: both specify the fully qualified name of the configuration class for the entire group.

properties: these are the individual child entries under each parent node—the settings to which values are assigned in the YAML file.

A property’s name is the child node’s name in the YAML configuration.

A property’s type is the data type of the corresponding field in the configuration class, such as java.lang.String.

A property’s description describes that node’s configuration setting.

A property’s defaultValue is used when the node is not configured.

A property’s sourceType is the fully qualified name of its configuration class.

Create the CustomConfigurationProperties Class

@Getter
@Setter
@ConfigurationProperties(prefix = "jack.sparrow")
public class CustomConfigurationProperties {

    // private String name;
    private Integer code;
    private Boolean check;

}

Create the CustomConfigurationComplexProperties Class

@Getter
@Setter
@ConfigurationProperties(prefix = "jack.sparrow.name")
public class CustomConfigurationComplexProperties {

    private Map<String,String> nameMap = new HashMap<>();
}

Note: in the JSON above, the second-level child node name has no value of its own, whereas the third-level node nameMap needs values. This requires two configuration classes, because prefix can only locate one level below itself and cannot reach deeper levels.

Configure the Application Class

@EnableConfigurationProperties({CustomConfigurationProperties.class, CustomConfigurationComplexProperties.class})
@SpringBootApplication
public class Spring01Application {

	public static void main(String[] args) {
		SpringApplication.run(Spring01Application.class, args);
	}
}

Configure the YAML File

jack:
  sparrow:
    check: false
    name:
      nameMap:
        jack: "this is jack"
        rose: "this is rose"
    code: 3

As shown below: IDEA suggesting custom configuration properties while editing YAML

Test Whether the Configuration Takes Effect

@Configuration
@ConditionalOnProperty(
        prefix = "jack.sparrow",
        name = {"enabled"},
        havingValue = "true",
        matchIfMissing = true
)
@AllArgsConstructor
public class CustomConfiguration implements EnvironmentAware {
    private final CustomConfigurationProperties properties;
    private final CustomConfigurationComplexProperties complexProperties;

    @Override
    public void setEnvironment(Environment environment) {
        String prefix = "jack.sparrow.";
        StandardEnvironment standardEnvironment = (StandardEnvironment) environment;
        this.getProValue(prefix,standardEnvironment);
    }


    private void getProValue(String prefix,Environment environment){
        String code = environment.getProperty(prefix + "code");
        System.out.println(code);
        Map<String, String> nameMap = complexProperties.getNameMap();
        nameMap.forEach((k,v) -> {
            System.out.println(k);
            System.out.println(v);
        });
        System.out.println(properties.getCheck());
    }
}

Start the application and watch the console to see the printed configuration values.

name (the name of a property configured in the JSON metadata) works with havingValue. The retrieved property value is compared with havingValue, and the configuration is loaded only if they match.

matchIfMissing controls whether the configuration can be loaded when that property is absent. If true, it loads normally even without the property; otherwise, an error occurs.

Create a Custom Auto-Configuration Class

With custom YAML configuration in place, how can we configure it automatically under certain conditions when another application adds our dependency? Many frameworks, including Alibaba’s Druid data source and Feign, provide a spring-boot-starter that performs auto-configuration when added as a dependency. How do we define our own auto-configuration class? The official Spring Boot documentation on auto-configuration explains the implementation in detail, from defining your own configuration to testing whether it takes effect. Example code. For my own custom auto-configuration, see this article.

References

Spring’s documentation on configuration metadata

SegmentFault article


Share this post:

Previous Post
Using ShardingSphere–ShardingJDBC (Part 3): Data Masking
Next Post
Getting Started with SkyWalking

Comments

Questions, corrections, and experiences are welcome. Sign in with GitHub to comment; both language versions share this discussion.

Comments are available on the live site only.