在 Spring Boot 中把 YAML 属性绑定到 Map

1、概览

本文将带你了解如何在 Spring Boot 中把 YAML 属性注入到 Map

2、Spring 中的 YAML 文件

使用 YAML 文件存储外部配置数据是 Spring 开发人员的常见做法。Spring 支持使用 YAML 作为 Properties 的替代。

Spring 底层使用 SnakeYAML 来解析 YAML。

话不多说,来看看典型的 YAML 文件是什么样的:

server:
  port: 8090
  application:
    name: myapplication
    url: http://myapplication.com

如你所见,YAML 文件不言自明,而且更易于人阅读。YAML 提供了一种精美而简洁的方式来存储层次化的配置数据。

默认情况下,Spring Boot 会在应用启动时从 application.propertiesapplication.yml 中读取配置属性。不过,可以使用 @PropertySource 来加载自定义 YAML 文件。

熟悉了 YAML 文件后,来看看如何在 Spring Boot 中将 YAML 属性注入到 Map 中。

3、将 YAML 属性注入到 Map

通过 @ConfigurationProperties 注解,Spring Boot 可轻松地将配置文件中的外部属性直接注入 Java 对象。

首先,在 application.yml 中定义一些 Key/Value 属性:

server:
  application:
    name: InjectMapFromYAML
    url: http://injectmapfromyaml.dev
    description: How To Inject a map from a YAML File in Spring Boot
  config:
    ips:
      - 10.10.10.10
      - 10.10.10.11
      - 10.10.10.12
      - 10.10.10.13
    filesystem:
      - /dev/root
      - /dev/md2
      - /dev/md4
  users: 
    root:
      username: root
      password: rootpass
    guest:
      username: guest
      password: guestpass

配置属性如上,接下来尝试将 application 映射为一个简单的 Map<String, String>。将 config 注入为一个 Map<String, List<String>>,将 users 映射为一个 Map,其中 Key 是 String,Value 是自定义(Credential)对象。

创建一个 Bean 类 ServerProperties,以封装将配置属性绑定到 Map 的逻辑:

@Component
@ConfigurationProperties(prefix = "server")
public class ServerProperties {

    private Map<String, String> application;
    private Map<String, List<String>> config;
    private Map<String, Credential> users;

    // Get、Set

    public static class Credential {

        private String username;
        private String password;
        
        // Get、Set
        
    }
}

如你所见,用 @ConfigurationProperties 注解了 ServerProperties 类,以告诉 Spring 将所有带有指定前缀(prefix)的属性映射到 ServerProperties 对象中。

最后,测试 YAML 属性是否被正确注入为 Map

@RunWith(SpringRunner.class)
@SpringBootTest
class MapFromYamlIntegrationTest {

    @Autowired
    private ServerProperties serverProperties;

    @Test
    public void whenYamlFileProvidedThenInjectSimpleMap() {
        assertThat(serverProperties.getApplication())
          .containsOnlyKeys("name", "url", "description");

        assertThat(serverProperties.getApplication()
          .get("name")).isEqualTo("InjectMapFromYAML");
    }

    @Test
    public void whenYamlFileProvidedThenInjectComplexMap() {
        assertThat(serverProperties.getConfig()).hasSize(2);

        assertThat(serverProperties.getConfig()
          .get("ips")
          .get(0)).isEqualTo("10.10.10.10");

        assertThat(serverProperties.getUsers()
          .get("root")
          .getUsername()).isEqualTo("root");
    }

}

4、@ConfigurationProperties 和 @Value

现在来比较一下 @ConfigurationProperties@Value

尽管这两种注解都可用于从配置文件注入属性,但它们之间却有很大的不同。这两个注解的主要区别在于各自的用途不同。

简而言之,@Value 允许通过 Key 直接注入特定属性值。然而,@ConfigurationProperties 注解将多个属性绑定到一个特定对象,并通过对象提供对属性的访问。

一般来说,在注入配置数据时,Spring 建议使用 @ConfigurationProperties 而不是 @Value@ConfigurationProperties 提供了一种将配置属性集中并分组到结构化对象中的好方法,可以将其注入到其他 Bean 中。

5、总结

本文介绍了如何在 Spring Boot 中把 YAML 属性绑定到 Map,还介绍了 @ConfigurationProperties@Value 之间的区别。


Ref:https://www.baeldung.com/spring-yaml-inject-map