把yml文件配置转换为Map<String, Object>方式存储开箱即用

曾经终败给现在 2024-04-23 02:47 55阅读 0赞

记录:385

场景:在Spring Boot微服务中,读取application.yml或者bootstrap.yml等yml文件配置,转换为Map方式存储,使用(key,value)键值对方式,开箱即用。

1.基础说明

1.1转换原因

使用snakeyaml框架的org.yaml.snakeyaml.Yaml,从微服务的../src/main/resources资源加载yml文件,会存储在Map mapFromYml中。

(1)yml文件配置示例

  1. server:
  2. servlet:
  3. context-path: /hub-example
  4. spring:
  5. jackson:
  6. time-zone: GMT+8

(2)Yaml加载Map存储方式

Yaml加载Map存储方式:按照yml文件格式,一个冒号前面字符串就是一个Map的key,一个冒号后面部分是一个Map,直到冒号后面是具体值时,才是一个具体Object。因此,Yaml加载的结果Map在里面嵌套了很多层Map,最后一层Map的value才是具体值。具体格式,可以参考如下图。

使用不足:Yaml加载的Map,(key,value)键值对无法直接使用,使用时需要多次遍历才能找到最后值。因此,需转换。

f42bfb59caf1f0fb44859a31b211e2e1.png

(3)把Yaml加载的Map转换为可以直接使用的Map

yml配置示例:

  1. server:
  2. servlet:
  3. context-path: /hub-example
  4. spring:
  5. jackson:
  6. time-zone: GMT+8

转换后存储方式:

spring.jackson.time-zone=GMT+8

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

转换后取值方式:

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

1.2核心依赖

(1)功能

使用snakeyaml框架加载yml文件。

(2)依赖包

jar包:snakeyaml-1.33.jar

pom.xml依赖:

  1. <dependency>
  2. <groupId>org.yaml</groupId>
  3. <artifactId>snakeyaml</artifactId>
  4. <version>1.33</version>
  5. </dependency>

2.示例一:根据yml文件名读取yml配置和转换为Map

2.1实现方法

  1. //1.从yml文件中加载
  2. public static Map<String, Object> loadFromYmlFile(String ymlFileName) {
  3. InputStream input = null;
  4. Map<String, Object> mapFromYml = null;
  5. if (StringUtils.isBlank(ymlFileName)) {
  6. return null;
  7. }
  8. try {
  9. ClassPathResource resource = new ClassPathResource(ymlFileName);
  10. input = resource.getInputStream();
  11. Yaml yaml = new Yaml();
  12. mapFromYml = yaml.loadAs(input, Map.class);
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. } finally {
  16. if (input != null) {
  17. try {
  18. input.close();
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. }
  24. return mapFromYml;
  25. }
  26. //2.第一层转换
  27. public static Map<String, Object> convertYml(Map<String, Object> mapFromYml) {
  28. Map<String, Object> map = mapFromYml;
  29. Map<String, Object> mapAfterConvert = new HashMap<>();
  30. map.forEach((key1, value1) -> {
  31. if (value1 instanceof Map) {
  32. mapAfterConvert.putAll(forEachYml(mapAfterConvert, key1, (Map) value1));
  33. } else {
  34. mapAfterConvert.put(key1, value1.toString());
  35. }
  36. });
  37. mapAfterConvert.forEach((key,value)->{
  38. System.out.println(key+"="+value);
  39. });
  40. return mapAfterConvert;
  41. }
  42. // 3.第二层转换(递归转换)
  43. public static Map<String, Object> forEachYml(Map<String, Object> mapAfterConvert, String key1, Map<String, Object> map) {
  44. map.forEach((key2, value2) -> {
  45. String strNew;
  46. if (StringUtils.isNotEmpty(key1)) {
  47. strNew = key1 + "." + key2;
  48. } else {
  49. strNew = key2;
  50. }
  51. if (value2 instanceof Map) {
  52. mapAfterConvert.putAll(forEachYml(mapAfterConvert, strNew, (Map) value2));
  53. } else {
  54. mapAfterConvert.put(strNew, value2);
  55. }
  56. });
  57. return mapAfterConvert;
  58. }
  59. // 4.转换为(key,value),直接使用版本
  60. public static Map<String, Object> getYmlAllConfig(String ymlFileName) {
  61. return convertYml(loadFromYmlFile(ymlFileName));
  62. }

2.2测试方法

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

3.示例二:读取yml文件使用单例方式存储转换结果Map

3.1实现方法

  1. public final class YmlFileUtil02 {
  2. private static YmlFileUtil02 ymlFileUtil = null;
  3. private String ymlFileName = "application.yml";
  4. // org.yaml.snakeyaml.Yaml从yml文件加载的Map(需逐层遍历才能定位到具体值)
  5. private Map<String, Object> mapFromYml = new HashMap<>();
  6. // 转换后的Map,直接使用getValue(key)获取值
  7. private Map<String, Object> mapAfterConvert = new HashMap<>();
  8. //从yml文件中加载与转换
  9. private YmlFileUtil02(String ymlFileName) {
  10. InputStream input = null;
  11. if (StringUtils.isNotBlank(ymlFileName)) {
  12. this.ymlFileName = ymlFileName;
  13. }
  14. try {
  15. ClassPathResource resource = new ClassPathResource(this.ymlFileName);
  16. input = resource.getInputStream();
  17. Yaml yaml = new Yaml();
  18. this.mapFromYml = yaml.loadAs(input, Map.class);
  19. convertYml();
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. } finally {
  23. if (input != null) {
  24. try {
  25. input.close();
  26. } catch (Exception e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  31. }
  32. // 第一层转换
  33. private void convertYml() {
  34. Map<String, Object> map = this.mapFromYml;
  35. map.forEach((key1, value1) -> {
  36. if (value1 instanceof Map) {
  37. this.mapAfterConvert.putAll(forEachYml(key1, (Map) value1));
  38. } else {
  39. this.mapAfterConvert.put(key1, value1.toString());
  40. }
  41. });
  42. }
  43. // 第二层转换(递归转换)
  44. private Map<String, Object> forEachYml(String key1, Map<String, Object> map) {
  45. map.forEach((key2, value2) -> {
  46. String strNew;
  47. if (StringUtils.isNotEmpty(key1)) {
  48. strNew = key1 + "." + key2;
  49. } else {
  50. strNew = key2;
  51. }
  52. if (value2 instanceof Map) {
  53. this.mapAfterConvert.putAll(this.forEachYml(strNew, (Map) value2));
  54. } else {
  55. this.mapAfterConvert.put(strNew, value2);
  56. }
  57. });
  58. return this.mapAfterConvert;
  59. }
  60. // 转换为(key,value),直接使用
  61. public Object getValue(String key) {
  62. return this.mapAfterConvert.get(key);
  63. }
  64. // 根据文件名创建单例对象
  65. public static YmlFileUtil02 getInstance(String ymlFileName) {
  66. if (ymlFileUtil == null) {
  67. Class<YmlFileUtil02> obj = YmlFileUtil02.class;
  68. synchronized (obj) {
  69. if (ymlFileUtil == null) {
  70. ymlFileUtil = new YmlFileUtil02(ymlFileName);
  71. }
  72. }
  73. }
  74. return ymlFileUtil;
  75. }
  76. }

3.2测试方法

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

4.测试yml文件

4.1文件名

application.yml

4.2文件内容

  1. server:
  2. servlet:
  3. context-path: /hub-example
  4. port: 18080
  5. spring:
  6. jackson:
  7. time-zone: GMT+8
  8. application:
  9. name: hub-example-custom
  10. cloud:
  11. nacos:
  12. server-addr: 127.0.0.1:8848
  13. username: nacos
  14. password: nacos
  15. namespace: d4f554cb-941e-40bc-85ce-f7a16c0dd4ba
  16. config:
  17. server-addr: 127.0.0.1:8848
  18. username: nacos
  19. password: nacos
  20. namespace: d4f554cb-941e-40bc-85ce-f7a16c0dd4ce
  21. group: DEFAULT_GROUP
  22. file-extension: yaml
  23. shared-configs:
  24. - dataId: hub01.yml
  25. refresh: true
  26. group: DEFAULT_GROUP
  27. - dataId: hub02.yml
  28. refresh: true
  29. group: DEFAULT_GROUP
  30. - dataId: hub03.yml
  31. refresh: true
  32. group: DEFAULT_GROUP

4.3注意事项

在yml文件中,以-短横线开头的配置,对应成Java对象是List类型。因此这类的(key,value)是这样的:

key=spring.cloud.config.shared-configs

value=ArrayList

dcc4f2474294a8e9a63b62ebe62c427a.png

以上,感谢。

2023年3月13日

发表评论

表情:
评论列表 (有 0 条评论,55人围观)

还没有评论,来说两句吧...

相关阅读

    相关 开箱的SpringBoot模板

    开箱即用的SpringBoot模板 前言 如果你从事的开发岗位是独立开发一个完整的项目的时候,我们需要前期做很多的开发准备,特别是使用比较多的技术栈的时候,我们前期

    相关 go语言开箱

    一、安装并配置环境 Windows 下可以使用 .msi 后缀(在下载列表中可以找到该文件,如go1.4.2.windows-amd64.msi)的安装包来安装。默认情况下