天天看點

一文教會你如何讓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"));
    }
}