Spring Boot自定義配置屬性源(PropertySource)
配置覆蓋優(yōu)于profile
在生產(chǎn)實(shí)踐中,配置覆蓋是解決不同環(huán)境不同配置的常用方法。比如用生產(chǎn)服務(wù)器上的配置文件覆蓋包內(nèi)的文件,或者使用中心化的配置服務(wù)來(lái)覆蓋默認(rèn)的業(yè)務(wù)配置。
相比于profile機(jī)制(比如maven的profile、spring boot的profile-specific properties),即不同環(huán)境使用不同的配置文件,覆蓋的方式更有優(yōu)勢(shì)。程序員在開(kāi)發(fā)時(shí)不需要關(guān)心生產(chǎn)環(huán)境數(shù)據(jù)庫(kù)的地址、賬號(hào)等信息,一次構(gòu)建即可在不同環(huán)境中運(yùn)行,而profile機(jī)制需要將生產(chǎn)環(huán)境的配置寫(xiě)到項(xiàng)目資源文件中,而且要為不同環(huán)境使用不同的構(gòu)建參數(shù)或者運(yùn)行參數(shù)。
Spring提供了靈活的配置擴(kuò)展能力,有多種方式將自定義的屬性源,將集成進(jìn)來(lái),可以輕松地實(shí)現(xiàn)配置覆蓋。
本文基于Spring Boot 1.4.8/Spring 4.3.12編寫(xiě)
使用@PropertySource注解實(shí)現(xiàn)自定義配置文件和配置覆蓋
@ConfigurationProperties @Configuration public class DemoProperties { // properties with getter/setters }
@PropertySource(value = { "test.properties", "file:/etc/test.properties", }, ignoreResourceNotFound = true) @Configuration public class DemoAutoConfiguration { @Autowired private DemoProperties demoProperties; @PostConstruct public void init() { System.out.println(demoProperties); } }
Spring支持使用PropertySource注解引入自定義配置文件,其中"test.properties"將使Spring從classpath下加載該文件,"file:/etc/test.properties"將使Spring從文件系統(tǒng)加載/etc/test.properties文件,ignoreResourceNotFound = true使Spring忽略文件加載失敗的異常,即配置文件是可選的。
同時(shí),由于"file:/etc/test.properties"位于"test.properties"之后,這使得文件系統(tǒng)的配置文件可以覆蓋classpath下的配置。
自定義屬性源工廠(chǎng)
如果想要更加靈活的自定義屬性源,比如實(shí)現(xiàn)從中心化的配置服務(wù)加載配置,可以通過(guò)實(shí)現(xiàn)PropertySourceFactory接口,并通過(guò)配置PropertySource注解的factory參數(shù)來(lái)實(shí)現(xiàn)。
@Configuration @PropertySource(value = ""/*placeholder*/, factory = CompositePropertySourceFactory.class) public class CompositeConfigAutoConfiguration { }
value字段用于指定配置源對(duì)應(yīng)的資源文件,如果不需要使用資源文件,可以配置為任意值,參數(shù)值將會(huì)被傳遞到factory參數(shù)的createPropertySource方法。
如果ignoreResourceNotFound字段指定為true,那么factory拋出的異常將被忽略,否則將導(dǎo)致啟動(dòng)失敗。有的時(shí)候,直接把啟動(dòng)失敗暴露出來(lái)不失為一種好的做法。
PropertySourceFactory接口的定義如下:
/** * Strategy interface for creating resource-based {@link PropertySource} wrappers. * * @author Juergen Hoeller * @since 4.3 * @see DefaultPropertySourceFactory */ public interface 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 */ PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException; }
需要注意的是PropertySourceFactory的加載時(shí)機(jī)早于Spring Beans容器,因此實(shí)現(xiàn)上不能依賴(lài)于Spring的IOC。
PropertySourceFactory要求實(shí)現(xiàn)類(lèi)返回PropertySource。PropertySource是Spring屬性(或者說(shuō)配置)功能的核心接口,有很多實(shí)現(xiàn),比如:
- ResourcePropertySource 從Resource加載PropertySource
- PropertiesPropertySource 從properties文件加載PropertySource
- SystemEnvironmentPropertySource 從系統(tǒng)環(huán)境變量加載PropertySource
- MapPropertySource 包裝一個(gè)Map為PropertySource(Adapter模塊)
- CompositePropertySource 支持將若干PropertySource進(jìn)行組合(Composite模式)
實(shí)際實(shí)現(xiàn)類(lèi)遠(yuǎn)不如這些,具體的可以閱讀Spring文檔或源碼。
在自定義屬性源時(shí)比較常用的是MapPropertySource和CompositePropertySource。
MapPropertySource可以用于將自己加載的屬性數(shù)據(jù)包裝,參考其構(gòu)造方法。
public MapPropertySource(String name, Map<String, Object> source) { super(name, source); }
后者可以通過(guò)組合裝載多個(gè)屬性源并自定義覆蓋順序。例如:
PropertySource<?> packageInsidePropertySource = packageInsidePropertySourceIterateLoader.loadPropertySource(compositePropertySource); compositePropertySource.addPropertySource(packageInsidePropertySource); PropertySource<?> outerFilePropertySource = outerFilePropertySourceIterateLoader.loadPropertySource(compositePropertySource); // 優(yōu)先級(jí)高于前者 compositePropertySource.addFirstPropertySource(outerFilePropertySource);
addFirstPropertySource方法可以設(shè)置傳入的PropertySource為最高優(yōu)先級(jí)(在此CompositePropertySource內(nèi)部),addPropertySource方法則相反,放在后面的優(yōu)先級(jí)更低。
加載依賴(lài)jar包中所有同名配置文件
直接從classpath加載配置文件,要求文件必須存在于classpath中??紤]在WEB項(xiàng)目中,如果文件存在于某個(gè)依賴(lài)的jar包中,即位于WEB-INF/lib/xxx.jar中,此時(shí)基于classpath無(wú)法直接加載。此時(shí)可以使用Spring提供的PathMatchingResourcePatternResolver,按資源名稱(chēng)掃描所有jar包來(lái)實(shí)現(xiàn)目的。
private List<Resource> getPackageInsideResourcesByPattern(String resourceName) throws IOException { String resourcePathPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + HbootConfigConstants.CONFIGS + resourceName; ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); return Arrays.asList(resourcePatternResolver.getResources(resourcePathPattern)); }
然后就可以使用ResourcePropertySource從Resource構(gòu)建PropertySource傳給Spring。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
DoytoQuery中的關(guān)聯(lián)查詢(xún)方案示例詳解
這篇文章主要為大家介紹了DoytoQuery中的關(guān)聯(lián)查詢(xún)方案示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12老生常談Java網(wǎng)絡(luò)編程TCP通信(必看篇)
下面小編就為大家?guī)?lái)一篇老生常談Java網(wǎng)絡(luò)編程TCP通信(必看篇)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05SpringBoot整合JWT實(shí)戰(zhàn)教程
JWT(JSON?Web?Token)是一種用于身份驗(yàn)證和授權(quán)的開(kāi)放標(biāo)準(zhǔn)(RFC?7519),它使用JSON格式傳輸信息,可以在不同系統(tǒng)之間安全地傳遞數(shù)據(jù),這篇文章主要介紹了SpringBoot整合JWT實(shí)戰(zhàn)教程,需要的朋友可以參考下2023-06-06SpringBoot配置默認(rèn)HikariCP數(shù)據(jù)源
咱們開(kāi)發(fā)項(xiàng)目的過(guò)程中用到很多的開(kāi)源數(shù)據(jù)庫(kù)鏈接池,比如druid、c3p0、BoneCP等等,本文主要介紹了SpringBoot配置默認(rèn)HikariCP數(shù)據(jù)源,具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11javaWeb用戶(hù)權(quán)限控制簡(jiǎn)單實(shí)現(xiàn)過(guò)程
這篇文章主要為大家詳細(xì)介紹了javaWeb用戶(hù)權(quán)限控制簡(jiǎn)單實(shí)現(xiàn)過(guò)程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08