美文网首页
记一则对SpringBoot@PropertySource不能解

记一则对SpringBoot@PropertySource不能解

作者: LoWang | 来源:发表于2019-03-22 09:52 被阅读0次

    scio

    https://github.com/rench/scio

    起因

    在项目中,有一个文件core.yml,里面存储了core模块的一些基础配置,该文件里面的写法有properties的写法也有yaml的写法。例如:

    ···
    scio.core.api.secrets: test,123456
    scio.core.sms.appKey=1d5123123165db5
    ···
    

    在eclipse编辑器中,经常会提示错误,也就是说yml文件中的语法有误。确实,scio.core.sms.appKey=1d5123123165db5这段的写法是properties的写法。但是启动程序,没有任何错误报出,看着不爽,就想把错误取消,所以把scio.core.sms.appKey=1d5123123165db5修改成scio.core.sms.appKey: "1d5123123165db5"。启动项目,junit测试报错了,提示appKey不存在。

    发现

    发现junit测试错误,根据问题找到校验appKey的业务逻辑,发现${scio.core.sms.appKey}获取到的appKey居然是带有引号的"1d5123123165db5"。那就奇怪了,按照yaml的写法,双引号和单引号只是区分是否转义字符串中的特殊符号,不会把双引号到值里面去的。跟踪发现,core.yml的引用是使用了@PropertySource({"classpath:core.yml"})进行解析的,通过查看@PropertySource注解的解释,如下:Given a file app.properties containing the key/value pair testbean.name=myTestBean, the following @Configuration classuses @PropertySource to contribute app.properties to the Environment's set of PropertySources.,由此可见,默认他是解析的properties文件,猜想,他并没有按照yaml的格式解析,若properties的解析也支持冒号分隔,那么把冒号后面的数据解析带有引号,也就能解释通了。

    解析

    • @PropertySource 的注解中,有一个factory属性,可指定一个自定义的PropertySourceFactory接口实现,用于解析指定的文件。默认的实现是DefaultPropertySourceFactory,继续跟进,使用了PropertiesLoaderUtils.loadProperties进行文件解析,所以默认就是使用Properties进行解析的。

    扩展

    • CompositePropertySourceFactory 查看了DefaultPropertySourceFactory的解析方法后,发现其支持properties文件的解析,跟进properties的load方法发现在解析时,分隔符是=或者:,虽说可以解析简单的yml格式内容,但是无法支持真正的yaml语法,可以对DefaultPropertySourceFactory进行扩展,支持两种格式混合解析。以下是主要代码
    package com.scio.cloud.cloudconfig;
    
    import java.io.IOException;
    import java.util.Optional;
    import java.util.Properties;
    
    import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
    import org.springframework.core.env.PropertiesPropertySource;
    import org.springframework.core.env.PropertySource;
    import org.springframework.core.io.support.DefaultPropertySourceFactory;
    import org.springframework.core.io.support.EncodedResource;
    /**
     * CompositePropertySourceFactory support properties and yaml file
     *
     * @author Wang.ch
     * @date 2019-03-22 09:30:15
     */
    public class CompositePropertySourceFactory extends DefaultPropertySourceFactory {
      @Override
      public PropertySource<?> createPropertySource(String name, EncodedResource resource)
          throws IOException {
        String sourceName = Optional.ofNullable(name).orElse(resource.getResource().getFilename());
        if (!resource.getResource().exists()) {
          // return an empty Properties
          return new PropertiesPropertySource(sourceName, new Properties());
        } else if (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml")) {
          Properties propertiesFromYaml = loadYaml(resource);
          return new PropertiesPropertySource(sourceName, propertiesFromYaml);
        } else {
          return super.createPropertySource(name, resource);
        }
      }
      /**
       * load yaml file to properties
       *
       * @param resource
       * @return
       * @throws IOException
       */
      private Properties loadYaml(EncodedResource resource) throws IOException {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(resource.getResource());
        factory.afterPropertiesSet();
        return factory.getObject();
      }
    }
    
    • @PropertySource
    @PropertySource(
        value = {"core.yml", "key.properties"},
        factory = CompositePropertySourceFactory.class)
    

    相关文章

      网友评论

          本文标题:记一则对SpringBoot@PropertySource不能解

          本文链接:https://www.haomeiwen.com/subject/xbakvqtx.html