Spring Boot 除 xml/yml 外,利用 SPI 支持对 json 配置文件的解析

2022/2/17 SPI

    继上一篇JDK/Dubbo/Spring 三种SPI机制解析之后,今天就在 Spring Boot 中,利用 SPI 支持对 json 配置文件的解析。

    SpringBoot 的配置文件内置支持 properties、xml、yml、yaml 几种格式,其中 properties 和 xml 对应的Loader类为 PropertiesPropertySourceLoader ,yml和yaml 对应的Loader类为 YamlPropertySourceLoader。

    了解了 Spring SPI 机制后,观察这2个类可以发现,都实现自接口 PropertySourceLoader 。所以我们要新增支持别的格式的配置文件,就可以通过实现接口 PropertySourceLoader 来实现了。

    参照 PropertiesPropertySourceLoader , 下面实现了一个 json 格式的配置文件 Loader类:

    /**
     * JSON格式配置文件加载器
     */
    public class JsonPropertySourceLoader implements PropertySourceLoader {
    
        public String[] getFileExtensions() {
            // 配置文件格式(扩展名)
            return new String[] { "json" };
        }
    
        public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
            if (resource == null || !resource.exists()) {
                return Collections.emptyList();
            }
            Map<String, Object> map = JSON.parseObject(resource.getInputStream(), Map.class);
            Map<String, Object> resutltMap = new HashMap<>();
            // 将json转为键值对
            parseMap("", resutltMap, map);
            return Collections.singletonList(return new MapPropertySource(name, result));
        }
    
        private void parseMap(String prefix, Map<String, Object> result, Map<String, Object> map) {
            if (prefix.length() > 0) {
                prefix += ".";
            }
            for (Map.Entry<String, Object> entrySet : map.entrySet()) {
                if (entrySet.getValue() instanceof Map) {
                    nestMap(prefix + entrySet.getKey(), result, (Map<String, Object>) entrySet.getValue());
                } else {
                    result.put(prefix + entrySet.getKey().toString(), entrySet.getValue());
                }
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    然后在 src/main/resources 中创建 META-INF/spring.factories 文件,内容为:

    org.springframework.boot.env.PropertySourceLoader=\
    com.shanhy.sboot.property.JsonPropertySourceLoader
    
    1
    2

    创建测试的配置文件 application.json

    {
        "custom": {
            "property": {
                "message": "测试数据"
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7

    创建验证结果的 HelloController.java

    @RestController
    public class HelloController {
    
        @Value("${custom.property.message}")
        private Object customProperty;
    
        @RequestMapping("/test")
        public Object test() {
            return customProperty;
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    启动工程服务,浏览器访问 http://localhost:8080/test 即可查看输出的结果为 “测试数据”;

      此生不换
      青鸟飞鱼