Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件

一、@PropertySource註解

@PropertySource加載指定的配置文件。

將一切配置全部寫在全局配置文件中,是不可想象的。項目中不可避免存在多個配置文件。

@PropertySource 可以根據需要加載指定的配置文件,將配置文件中的屬性注入到系統環境中。@ConfigurationProperties 默認從全局配置文件獲取配置。

這裡將person的屬性配置單獨寫在person.yml文件中,並從全局配置文件中註釋掉person的屬性配置。

因為yaml語法很簡潔,寫yaml配置文件也比較方便。

通過@PropertySource註解讀取配置文件的屬性,進行映射,習慣上用properties配置文件是沒問題的。但是,換成yaml文件,發現都讀取不到屬性值。

這是因為@PropertySource默認不支持yaml讀取,我們改成@Value註解也是可以讀取的,不過屬性一堆的話,一個一個讀取也是很繁瑣的。不過,可以通過自定義開發來實現對yaml配置文件的支持。



二、為什麼@PropertySource 註解默認不支持yaml配置文件?

下面簡單分析一下源碼。

1. @PropertySource 源碼

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件

根據上面的註釋,默認使用DefaultPropertySourceFactory類作為資源文件加載類。

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件

進一步調用Spring框架底層的PropertiesLoaderUtils工具類進行讀取資源文件。

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件

然後調用DefaultPropertiesPersister的load方法:

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件


最終加載配置文件的方法,就是下面的load0()方法。

從源碼可以看出,這個方法是一行一行地讀取,然後根據冒號、等於號、空格等進行校驗,經過一系列遍歷之後獲取key和value,而yaml語法是以縮進來辨別的,這個方法不支持yaml文件的讀取。

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件


三、自定義yaml配置文件讀取的工廠類

模仿DefaultPropertySourceFactory寫一個yaml配置文件讀取的工廠類。

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件

完整代碼如下所示:

package com.rickie.springboot.core;


import org.springframework.boot.env.YamlPropertySourceLoader;

import org.springframework.core.env.PropertiesPropertySource;

import org.springframework.core.env.PropertySource;

import org.springframework.core.io.support.EncodedResource;

import org.springframework.core.io.support.PropertySourceFactory;


import java.io.IOException;

import java.util.List;

import java.util.Optional;

import java.util.Properties;


public class YmlPropertyResourceFactory implements PropertySourceFactory {


@Override

public PropertySource> createPropertySource(String name, EncodedResource encodedResource) throws IOException {

String resourceName = Optional.ofNullable(name).orElse(encodedResource.getResource().getFilename());


if(resourceName.endsWith(".yml") || resourceName.endsWith(".yaml")) {

List<propertysource>> yamlSources = new YamlPropertySourceLoader().load(resourceName, encodedResource.getResource());/<propertysource>

return yamlSources.get(0);

} else {

return new PropertiesPropertySource(resourceName, new Properties());

}

}

}



四、編寫Person類和person.yml 配置文件

寫個bean類進行屬性映射,注意替換一下默認的factory參數,factory = YmlPropertyResourceFactory.class。

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件


@Component組件

注入Spring容器,只有Spring容器中的組件才能使用@ConfigurationProperties功能;


@PropertySource(value = "classpath:person.yml",encoding = "utf-8",factory = YmlPropertyResourceFactory.class)

加載指定的配置文件;獲取的是person.properties 這個配置文件下的配置信息;

factory = YmlPropertyResourceFactory.class 設置使用自定義的配置文件讀取的工廠類;


@ConfigurationProperties(prefix = "person")

告訴SpringBoot將本類中的相關配置與yml文件中的配置綁定,並獲取配置前綴person下的配置項。


下面是person.yml 配置文件,同時將application.yml 中的person配置項註釋掉。

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件



五、測試驗證

編寫單元測試類,進行測試驗證。

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件

測試結果如下所示 :

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件



六、擴展PropertyResourceFactory 工廠類

如果既要支持原來的yml,又要支持properties,就可以將PropertyResourceFactory類進行改寫一下。

package com.rickie.springboot.core;


import org.springframework.boot.env.YamlPropertySourceLoader;

import org.springframework.core.env.PropertySource;

import org.springframework.core.io.support.DefaultPropertySourceFactory;

import org.springframework.core.io.support.EncodedResource;

import org.springframework.core.io.support.PropertySourceFactory;

import org.springframework.lang.Nullable;


import java.io.IOException;

import java.util.List;

import java.util.Optional;


public class CommonPropertyResourceFactory implements PropertySourceFactory {

/**

* Create a {@link PropertySource} that wraps the given resource.

*

* @param name the name of the property source

* @param resource the resource (potentially encoded) to wrap

* @return the new {@link PropertySource} (never {@code null})

* @throws IOException if resource resolution failed

*/

@Override

public PropertySource> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {

String resourceName = Optional.ofNullable(name).orElse(resource.getResource().getFilename());

if (resourceName.endsWith(".yml") || resourceName.endsWith(".yaml")) {

List<propertysource>> yamlSources = new YamlPropertySourceLoader().load(resourceName, resource.getResource());/<propertysource>

return yamlSources.get(0);

} else {

return new DefaultPropertySourceFactory().createPropertySource(name, resource);

}

}

}

這個類就可以支持原來的properties文件,也可以支持yml文件。

調用的時候,要改一下factory參數:

@PropertySource(value = "classpath:person.yml",encoding = "utf-8",factory = CommonPropertyResourceFactory.class)

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件


還可以編寫Rest方法進行驗證,如下所示:

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件

運行時返回JSON信息如下所示:

Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件


分享到:


相關文章: