Convert the yml file configuration to Map<String, Object> storage out of the box

Records : 385

Scenario : In Spring Boot microservices, read application.yml or bootstrap.yml and other yml file configurations, convert them to Map<String, Object> storage, use (key, value) key-value pairs, and use them out of the box.

1. Basic description

1.1 Reasons for conversion

Use the org.yaml.snakeyaml.Yaml of the snakeyaml framework to load the yml file from the ../src/main/resources resource of the microservice, and store it in Map<String, Object> mapFromYml.

(1) yml file configuration example

server:
  servlet:
    context-path: /hub-example
spring:
  jackson:
    time-zone: GMT+8

(2) Yaml loading Map storage method

Yaml loads Map storage method: According to the yml file format, a character string before a colon is a key of a Map, and the part after a colon is a Map, until the colon is followed by a specific value, it is a specific Object. Therefore, the result Map<String, Object> loaded by Yaml has many layers of Maps nested in it, and the value of the last layer of Maps is the specific value. For the specific format, please refer to the figure below.

Insufficient usage: The (key, value) key-value pair of the Map loaded by Yaml cannot be used directly, and it needs to traverse multiple times to find the final value. Therefore, conversion is required.

(3) Convert the Map loaded by Yaml into a Map that can be used directly

yml configuration example:

server:
  servlet:
    context-path: /hub-example
spring:
  jackson:
    time-zone: GMT+8

Storage method after conversion:

spring.jackson.time-zone=GMT+8

server.servlet.context-path=/hub-example

How to get value after conversion:

Object value = Map.get(“spring.jackson.time-zone”)

1.2 Core dependencies

(1) Function

Load the yml file using the snakeyaml framework.

(2) Dependent packages

jar包:snakeyaml-1.33.jar

pom.xml depends on:

<dependency>
  <groupId>org.yaml</groupId>
  <artifactId>snakeyaml</artifactId>
  <version>1.33</version>
</dependency>

2. Example 1: Read the yml configuration and convert it to Map<String, Object> according to the yml file name

2.1 Implementation method

//1.从yml文件中加载
public static Map<String, Object> loadFromYmlFile(String ymlFileName) {
  InputStream input = null;
  Map<String, Object> mapFromYml = null;
  if (StringUtils.isBlank(ymlFileName)) {
      return null;
  }
  try {
      ClassPathResource resource = new ClassPathResource(ymlFileName);
      input = resource.getInputStream();
      Yaml yaml = new Yaml();
      mapFromYml = yaml.loadAs(input, Map.class);
  } catch (Exception e) {
      e.printStackTrace();
  } finally {
      if (input != null) {
          try {
              input.close();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  }
  return mapFromYml;
}
//2.第一层转换
public static Map<String, Object> convertYml(Map<String, Object> mapFromYml) {
  Map<String, Object> map = mapFromYml;
  Map<String, Object> mapAfterConvert = new HashMap<>();
  map.forEach((key1, value1) -> {
      if (value1 instanceof Map) {
          mapAfterConvert.putAll(forEachYml(mapAfterConvert, key1, (Map) value1));
      } else {
          mapAfterConvert.put(key1, value1.toString());
      }
  });
  mapAfterConvert.forEach((key,value)->{
      System.out.println(key+"="+value);
  });
  return mapAfterConvert;
}
// 3.第二层转换(递归转换)
public static Map<String, Object> forEachYml(Map<String, Object> mapAfterConvert, String key1, Map<String, Object> map) {
  map.forEach((key2, value2) -> {
      String strNew;
      if (StringUtils.isNotEmpty(key1)) {
          strNew = key1 + "." + key2;
      } else {
          strNew = key2;
      }
      if (value2 instanceof Map) {
          mapAfterConvert.putAll(forEachYml(mapAfterConvert, strNew, (Map) value2));
      } else {
          mapAfterConvert.put(strNew, value2);
      }
  });
  return mapAfterConvert;
}
// 4.转换为(key,value),直接使用版本
public static Map<String, Object> getYmlAllConfig(String ymlFileName) {
    return convertYml(loadFromYmlFile(ymlFileName));
}

2.2 Test method

public static void main(String[] args) {
  Map<String, Object> application = getYmlAllConfig("application.yml");
}

3. Example 2: Read the yml file and use the singleton method to store the conversion result Map<String, Object>

3.1 Implementation method

public final class YmlFileUtil02 {
  private static YmlFileUtil02 ymlFileUtil = null;
  private String ymlFileName = "application.yml";
  // org.yaml.snakeyaml.Yaml从yml文件加载的Map(需逐层遍历才能定位到具体值)
  private Map<String, Object> mapFromYml = new HashMap<>();
  // 转换后的Map,直接使用getValue(key)获取值
  private Map<String, Object> mapAfterConvert = new HashMap<>();
  //从yml文件中加载与转换
  private YmlFileUtil02(String ymlFileName) {
    InputStream input = null;
    if (StringUtils.isNotBlank(ymlFileName)) {
        this.ymlFileName = ymlFileName;
    }
    try {
        ClassPathResource resource = new ClassPathResource(this.ymlFileName);
        input = resource.getInputStream();
        Yaml yaml = new Yaml();
        this.mapFromYml = yaml.loadAs(input, Map.class);
        convertYml();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (input != null) {
            try {
                input.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
  }
  // 第一层转换
  private void convertYml() {
    Map<String, Object> map = this.mapFromYml;
    map.forEach((key1, value1) -> {
        if (value1 instanceof Map) {
            this.mapAfterConvert.putAll(forEachYml(key1, (Map) value1));
        } else {
            this.mapAfterConvert.put(key1, value1.toString());
        }
    });
  }
  // 第二层转换(递归转换)
  private Map<String, Object> forEachYml(String key1, Map<String, Object> map) {
    map.forEach((key2, value2) -> {
        String strNew;
        if (StringUtils.isNotEmpty(key1)) {
            strNew = key1 + "." + key2;
        } else {
            strNew = key2;
        }
        if (value2 instanceof Map) {
            this.mapAfterConvert.putAll(this.forEachYml(strNew, (Map) value2));
        } else {
            this.mapAfterConvert.put(strNew, value2);
        }
    });
    return this.mapAfterConvert;
  }
  // 转换为(key,value),直接使用
  public Object getValue(String key) {
    return this.mapAfterConvert.get(key);
  }
      // 根据文件名创建单例对象
  public static YmlFileUtil02 getInstance(String ymlFileName) {
    if (ymlFileUtil == null) {
        Class<YmlFileUtil02> obj = YmlFileUtil02.class;
        synchronized (obj) {
            if (ymlFileUtil == null) {
                ymlFileUtil = new YmlFileUtil02(ymlFileName);
            }
        }
    }
    return ymlFileUtil;
  }
}

3.2 Test method

public static void main(String[] args) {
  YmlFileUtil02 ymlInstance = YmlFileUtil02.getInstance("application.yml");
  System.out.println("server.port=" + ymlInstance.getValue("server.port"));
  System.out.println("spring.jackson.time-zone=" + ymlInstance.getValue("spring.jackson.time-zone"));
}

4. Test the yml file

4.1 File name

application.yml

4.2 File content

server:
  servlet:
    context-path: /hub-example
  port: 18080
spring:
  jackson:
    time-zone: GMT+8
  application:
    name: hub-example-custom
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      username: nacos
      password: nacos
      namespace: d4f554cb-941e-40bc-85ce-f7a16c0dd4ba
    config:
      server-addr: 127.0.0.1:8848
      username: nacos
      password: nacos
      namespace: d4f554cb-941e-40bc-85ce-f7a16c0dd4ce
      group: DEFAULT_GROUP
      file-extension: yaml
      shared-configs:
        - dataId: hub01.yml
          refresh: true
          group: DEFAULT_GROUP
        - dataId: hub02.yml
          refresh: true
          group: DEFAULT_GROUP
        - dataId: hub03.yml
          refresh: true
          group: DEFAULT_GROUP

4.3 Precautions

In the yml file, the configuration starting with -dash corresponds to the Java object being of List type. So the (key, value) of this class looks like this:

key=spring.cloud.config.shared-configs

value=ArrayList

Above, thanks.

March 13, 2023

Guess you like

Origin blog.csdn.net/zhangbeizhen18/article/details/129507834