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的解析也支持冒号分隔,那么把冒号后面的数据解析带有引号,也就能解释通了。
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