一、@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配置文件](http://p2.ttnews.xyz/loading.gif)
根據上面的註釋,默認使用DefaultPropertySourceFactory類作為資源文件加載類。
![Spring Boot中通過@PropertySource註解讀取yaml或yml配置文件](http://p2.ttnews.xyz/loading.gif)
進一步調用Spring框架底層的PropertiesLoaderUtils工具類進行讀取資源文件。
然後調用DefaultPropertiesPersister的load方法:
最終加載配置文件的方法,就是下面的load0()方法。
從源碼可以看出,這個方法是一行一行地讀取,然後根據冒號、等於號、空格等進行校驗,經過一系列遍歷之後獲取key和value,而yaml語法是以縮進來辨別的,這個方法不支持yaml文件的讀取。
三、自定義yaml配置文件讀取的工廠類
模仿DefaultPropertySourceFactory寫一個yaml配置文件讀取的工廠類。
完整代碼如下所示:
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。
@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配置項註釋掉。
五、測試驗證
編寫單元測試類,進行測試驗證。
測試結果如下所示 :
六、擴展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)
還可以編寫Rest方法進行驗證,如下所示:
運行時返回JSON信息如下所示:
閱讀更多 軟件架構 的文章