«1. Обзор

В этом кратком руководстве мы подробно рассмотрим, как внедрить карту из файла YAML в Spring Boot.

Во-первых, мы начнем с небольшого понимания файлов YAML в Spring Framework. Затем мы продемонстрируем на практическом примере, как связать свойства YAML с картой.

2. Файлы YAML в Spring Framework

Использование файлов YAML для хранения внешних данных конфигурации является обычной практикой среди разработчиков Spring. По сути, Spring поддерживает документы YAML в качестве альтернативы свойствам и использует SnakeYAML для их анализа.

Без лишних слов давайте посмотрим, как выглядит типичный файл YAML:

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

Как мы видим, файл YAML говорит сам за себя и более удобочитаем. На самом деле YAML предоставляет изящный и лаконичный способ хранения иерархических данных конфигурации.

По умолчанию Spring Boot считывает свойства конфигурации из application.properties или application.yml при запуске приложения. Однако мы можем использовать @PropertySource для загрузки пользовательского файла YAML.

Теперь, когда мы знакомы с тем, что такое файл YAML, давайте посмотрим, как внедрить свойства YAML в качестве карты в Spring Boot.

3. Как внедрить карту из файла YAML

Spring Boot вывел экстернализацию данных на новый уровень, предоставив удобную аннотацию под названием @ConfigurationProperties. Эта аннотация введена для простого внедрения внешних свойств из файлов конфигурации непосредственно в объекты Java.

В этом разделе мы подробно рассмотрим, как связать свойства YAML с классом компонента с помощью аннотации @ConfigurationProperties.

Во-первых, давайте определим некоторые свойства ключ-значение в application.yml:

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

В этом примере мы попробуем отобразить приложение в простой Map\u003cString, String\u003e. Точно так же мы введем сведения о конфигурации в виде Map\u003cString, List\u003cString\u003e\u003e и пользователей в виде Map со строковыми ключами и объектами, принадлежащими определенному пользователем классу — Credential — в качестве значений.

Во-вторых, давайте создадим класс bean-компонента — ServerProperties — для инкапсуляции логики привязки наших свойств конфигурации к Maps:

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

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

    // getters and setters

    public static class Credential {
    	
        private String username;
        private String password;
        
        // getters and setters
        
    }
}

Как мы видим, мы украсили класс ServerProperties @ConfigurationProperties. Таким образом, мы говорим Spring сопоставить все свойства с указанным префиксом с объектом ServerProperties.

Напомним, что наше приложение также должно быть включено для свойств конфигурации, хотя это делается автоматически в большинстве приложений Spring Boot.

Наконец, давайте проверим, правильно ли наши свойства YAML вводятся как карты:

@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 позволяет нам напрямую вводить конкретное значение свойства по его ключу. Однако аннотация @ConfigurationProperties связывает несколько свойств с конкретным объектом и обеспечивает доступ к свойствам через сопоставленный объект.

В общем, Spring рекомендует использовать @ConfigurationProperties вместо @Value, когда дело доходит до внедрения данных конфигурации. @ConfigurationProperties предлагает отличный способ централизовать и сгруппировать свойства конфигурации в структурированном объекте, который мы можем позже внедрить в другие bean-компоненты.

5. Заключение

Подводя итог, мы сначала объяснили, как внедрить карту из файла YAML в Spring Boot. Затем мы выделили разницу между @ConfigurationProperties и @Value.

Как обычно, полный исходный код статьи доступен на GitHub.