天天看点

一文教会你如何让spring @PropertySource支持读取yaml文件背景介绍实现思路具体实现进阶思考

一文教会你如何让spring @PropertySource支持读取yaml文件

  • 背景介绍
  • 实现思路
  • 具体实现
    • 使用演示
  • 进阶思考
    • 使用演示

背景介绍

通过之前的文章(点击查看)我们已经知道@PropertySource默认支持读取properties文件和xml文件,如果我们想让@PropertySource支持yaml文件的话,需要编写自定义factory。今天我们就来编写一个自定义的factory来实现这个功能。

实现思路

public class DefaultPropertySourceFactory implements PropertySourceFactory {
    public DefaultPropertySourceFactory() {
    }

    public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
        return name != null ? new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource);
    }
}
           

@PropertySource默认使用的factory是DefaultPropertySourceFactory。从源码中,我们可以看到,自定义factory需要实现PropertySourceFactory接口的createPropertySource方法。

另外spring自带了YamlPropertiesFactoryBean类,这个类提供了将yaml配置文件解析为Properties的能力,借助这个类,我们就可以编写支持yaml文件的factory。

具体实现

public class YamlPropertySourceFactory implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
    	// 如果没有传入名称则取文件名
        String sourceName = name != null ? name : resource.getResource().getFilename();

		// 新建FactoryBean解析配置文件
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(resource.getResource());
		// 返回解析后的结果
        return new PropertiesPropertySource(sourceName, factory.getObject());
    }
}
           

使用演示

test.yaml文件

actor:
  name: li.zhou
  age: 18
           
@SpringBootApplication
@PropertySource(value = {"file:D:\\test.yml"}, factory = YamlPropertySourceFactory.class)
public class SpringPropertyApplication {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringPropertyApplication.class, args);

        Environment environment = applicationContext.getEnvironment();
        // 输出:li.zhou
        System.out.println(environment.getProperty("actor.name"));
    }
}
           

进阶思考

虽然yaml文件是支持了,但是和properties与xml是割裂的,无法混合使用。于是我们在原来的基础上进一步编写factory支持3种格式的混合使用。

public class SmartPropertySourceFactory extends DefaultPropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        String sourceName = name != null ? name : resource.getResource().getFilename();
        if (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml")) {
            YamlPropertySourceFactory yamlPropertySourceFactory = new YamlPropertySourceFactory();
            return yamlPropertySourceFactory.createPropertySource(name, resource);
        } else {
            return super.createPropertySource(name, resource);
        }
    }
}
           

使用演示

test1.properties

properties.name=li.zhou
           
@SpringBootApplication
@PropertySource(value = {"file:D:\\test.yml", "file:D:\\test1.properties"}, 
        factory = SmartPropertySourceFactory.class)
public class SpringPropertyApplication {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringPropertyApplication.class, args);

        Environment environment = applicationContext.getEnvironment();
        // 打印均为li.zhou
        System.out.println(environment.getProperty("actor.name"));
        System.out.println(environment.getProperty("properties.name"));
    }
}