springcloud config配置讀取優(yōu)先級(jí)過程詳解
情景描述
最近在修復(fù)Eureka的靜態(tài)頁面加載不出的缺陷時(shí),最終發(fā)現(xiàn)是遠(yuǎn)程GIT倉(cāng)庫(kù)將靜態(tài)資源訪問方式配置給禁用了(spring.resources.add-mappings=false)。雖然最后直接修改遠(yuǎn)程GIT倉(cāng)庫(kù)的此配置項(xiàng)給解決了(spring.resources.add-mappings=true),但是從中牽涉出的配置讀取優(yōu)先級(jí)我們必須好好的再回顧下
springcloud config讀取倉(cāng)庫(kù)配置
通過config client模塊來讀取遠(yuǎn)程的倉(cāng)庫(kù)配置,只需要在boostrap.properties文件中配置如下屬性即可
spring.application.name=eureka spring.cloud.config.uri=http://localhost:8888 spring.cloud.config.name=dev spring.cloud.config.username=dev spring.cloud.config.password=dev
其就會(huì)以GET方式去請(qǐng)求http://localhost:8888/eureka/dev地址從而將配置拉取下來。
當(dāng)然上述的API地址也是需要被訪問服務(wù)器部署了config server服務(wù)方可調(diào)用,具體的細(xì)節(jié)就不展開了
外部源讀取優(yōu)先級(jí)
我們都知道spring的配置屬性管理均是存放在Enviroment對(duì)象中,就以普通項(xiàng)目StandardEnvironment為例,其配置的存放順序可羅列如下
順位 | key | 來源 | 說明 |
---|---|---|---|
1 | commandLineArgs | 傳入main函數(shù)的參數(shù)列表 | Program arguments |
2 | systemProperties | System.getProperties() | JDK屬性列表、操作系統(tǒng)屬性、-D開頭的VM屬性等 |
3 | systemEnvironment | System.getEnv() | 環(huán)境屬性,例如JAVA_HOME/M2_HOME |
4 | ${file_name} | 配置文件 | 例如application.yml |
5 | defaultProperties | SpringApplicationBuilder#properties() |
那么遠(yuǎn)程讀取的配置的存放應(yīng)該放在上述的哪個(gè)位置呢?
我們都知道boostrap上下文通過暴露org.springframework.cloud.bootstrap.config.PropertySourceLocator接口來方便集成第三方的外部源配置讀取,比如本文提及的config client模塊中的org.springframework.cloud.config.client.ConfigServicePropertySourceLocator實(shí)現(xiàn)類。
但最終將外部源配置讀取以及插入至Environment對(duì)象中則是通過org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration類來完成的。
PropertySourceBootstrapConfiguration
此類也是ApplicationContextInitializer接口的實(shí)現(xiàn)類,閱讀過cloud源碼的都知道,此類被調(diào)用是在子類上下文初始化的時(shí)候,我們主要看下其復(fù)寫的initialize()方法
@Override public void initialize(ConfigurableApplicationContext applicationContext) { CompositePropertySource composite = new CompositePropertySource( BOOTSTRAP_PROPERTY_SOURCE_NAME); // 對(duì)在boostrap上下文類型為PropertySourceLocator的bean集合進(jìn)行排序 AnnotationAwareOrderComparator.sort(this.propertySourceLocators); boolean empty = true; ConfigurableEnvironment environment = applicationContext.getEnvironment(); for (PropertySourceLocator locator : this.propertySourceLocators) { PropertySource<?> source = null; // 讀取外部配置源 source = locator.locate(environment); if (source == null) { continue; } logger.info("Located property source: " + source); composite.addPropertySource(source); empty = false; } if (!empty) { MutablePropertySources propertySources = environment.getPropertySources(); String logConfig = environment.resolvePlaceholders("${logging.config:}"); LogFile logFile = LogFile.get(environment); if (propertySources.contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) { propertySources.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME); } // 插入至Environment環(huán)境對(duì)象中 insertPropertySources(propertySources, composite); reinitializeLoggingSystem(environment, logConfig, logFile); setLogLevels(applicationContext, environment); handleIncludedProfiles(environment); } }
直接觀察對(duì)應(yīng)的insertPropertySources()方法
private void insertPropertySources(MutablePropertySources propertySources, CompositePropertySource composite) { // 外部源配置集合 MutablePropertySources incoming = new MutablePropertySources(); incoming.addFirst(composite); PropertySourceBootstrapProperties remoteProperties = new PropertySourceBootstrapProperties(); // 從外部源配置源集合中讀取PropertySourceBootstrapProperties的相關(guān)屬性 // 例如spring.cloud.config.overrideSystemProperties等屬性 Binder.get(environment(incoming)).bind("spring.cloud.config", Bindable.ofInstance(remoteProperties)); // spring.cloud.config.allow-override=false或者spring.cloud.config.override-none=false且spring.cloud.config.override-system-properties=true if (!remoteProperties.isAllowOverride() || (!remoteProperties.isOverrideNone() && remoteProperties.isOverrideSystemProperties())) { propertySources.addFirst(composite); return; } // spring.cloud.config.override-none=true則處于最低讀取位 if (remoteProperties.isOverrideNone()) { propertySources.addLast(composite); return; } // 根據(jù)spring.cloud.config.override-system-properties屬性判斷是放在systemProperties前還是后 if (propertySources .contains(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)) { if (!remoteProperties.isOverrideSystemProperties()) { propertySources.addAfter( StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, composite); } else { propertySources.addBefore( StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, composite); } } else { propertySources.addLast(composite); } }
對(duì)上述的代碼描述作下總結(jié)
1.上述的配置屬性均會(huì)映射到PropertySourceBootstrapProperties實(shí)體類中,且其中的默認(rèn)值羅列如下
屬性 | 默認(rèn)值 | 說明 |
---|---|---|
spring.cloud.config.allow-override | true | 外部源配置是否可被覆蓋 |
spring.cloud.config.override-none | false | 外部源配置是否不覆蓋任何源 |
spring.cloud.config.override-system-properties | true | 外部源配置是否可覆蓋本地屬性 |
2.針對(duì)相應(yīng)的屬性的值對(duì)應(yīng)的外部源在Environment對(duì)象中的讀取優(yōu)先級(jí),羅列如下
屬性 | 讀取優(yōu)先級(jí) |
---|---|
spring.cloud.config.allow-override=false | 最高 |
spring.cloud.config.override-none=false&&spring.cloud.config.override-system-properties=true | 最高(默認(rèn)) |
spring.cloud.config.override-none=true | 最低 |
spring上下文無systemEnvironment屬性 | 最低 |
spring上下文有systemEnvironment屬性 && spring.cloud.config.override-system-properties=false | 在systemEnvironment之后 |
spring上下文有systemEnvironment屬性 && spring.cloud.config.override-system-properties=false | 在systemEnvironment之前 |
即默認(rèn)情況下,外部源的配置屬性的讀取優(yōu)先級(jí)是最高的。
且除了spring.cloud.config.override-none=true的情況下,其他情況下外部源的讀取優(yōu)先級(jí)均比本地配置文件高。
Note:值得注意的是,如果用戶想復(fù)寫上述的屬性,則放在bootstrap.yml|application.yml配置文件中是無效的,根據(jù)源碼分析只能是自定義一個(gè)PropertySourceLocator接口實(shí)現(xiàn)類并放置在相應(yīng)的spring.factories文件中方可生效。
自定義PropertySourceLocator接口
針對(duì)上文描述,假設(shè)有這么一個(gè)場(chǎng)景,遠(yuǎn)程倉(cāng)庫(kù)的配置都是公有的,我們也不能修改它,我們只在項(xiàng)目中去復(fù)寫相應(yīng)的配置以達(dá)到兼容的目的。那么用戶就需要自定義去編寫接口了
1.編寫PropertySourceLocator接口實(shí)現(xiàn)類
package com.example.configdemo.propertysource; import org.springframework.cloud.bootstrap.config.PropertySourceLocator; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; import java.util.HashMap; import java.util.Map; /** * @author nanco * @create 19/9/22 * @description 自定義的PropertySourceLocator的順序應(yīng)該要比遠(yuǎn)程倉(cāng)庫(kù)讀取方式要優(yōu)先 * @see org.springframework.cloud.config.client.ConfigServicePropertySourceLocator */ @Order(value = Ordered.HIGHEST_PRECEDENCE + 1) public class CustomPropertySourceLocator implements PropertySourceLocator { private static final String OVERRIDE_ADD_MAPPING = "spring.resources.add-mappings"; @Override public PropertySource<?> locate(Environment environment) { Map<String, Object> customMap = new HashMap<>(2); // 遠(yuǎn)程倉(cāng)庫(kù)此配置為false,本地進(jìn)行復(fù)寫 customMap.put(OVERRIDE_ADD_MAPPING, "true"); return new MapPropertySource("custom", customMap); } }
2.編寫B(tài)ootstrapConfiguration
package com.example.configdemo.propertysource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author nanco * @create 19/9/22 */ @Configuration public class CustomBootstrapConfiguration { @Bean("customPropertySourceLocator") public CustomPropertySourceLocator propertySourceLocator() { return new CustomPropertySourceLocator(); } }
3.在src\main\resources目錄下創(chuàng)建META-INF\spring.factories文件
# Bootstrap components org.springframework.cloud.bootstrap.BootstrapConfiguration=\ com.example.configdemo.propertysource.CustomBootstrapConfiguration
4.運(yùn)行main函數(shù)即可
小結(jié)
默認(rèn)情況下,外部源配置擁有最高的優(yōu)先級(jí)。在spring.cloud.config.override-none=false的情況下,外部源配置也比本地文件擁有更高的優(yōu)先級(jí)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
安裝多個(gè)版本JDK后使用時(shí)的切換方法總結(jié)
我們平時(shí)在window上做開發(fā)的時(shí)候,可能需要同時(shí)開發(fā)兩個(gè)甚至多個(gè)項(xiàng)目,有時(shí)不同的項(xiàng)目對(duì)JDK的版本要求有區(qū)別,下面這篇文章主要給大家介紹了安裝多個(gè)版本JDK后使用的切換方法,需要的朋友可以參考借鑒,下面來一起看看吧。2017-01-01springboot啟動(dòng)后卡住無日志的幾種情況小結(jié)
這篇文章主要介紹了springboot啟動(dòng)后卡住無日志的幾種情況小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java組件FileUpload上傳文件實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Java組件FileUpload上傳文件實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06SpringBoot如何優(yōu)雅的處理重復(fù)請(qǐng)求
對(duì)于一些用戶請(qǐng)求,在某些情況下是可能重復(fù)發(fā)送的,如果是查詢類操作并無大礙,但其中有些是涉及寫入操作的,一旦重復(fù)了,可能會(huì)導(dǎo)致很嚴(yán)重的后果,所以本文給大家介紹了SpringBoot優(yōu)雅的處理重復(fù)請(qǐng)求的方法,需要的朋友可以參考下2023-12-12Java類成員訪問權(quán)限控制知識(shí)總結(jié)
這篇文章主要介紹了Java類成員訪問權(quán)限控制知識(shí)總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04java實(shí)現(xiàn)HttpClient異步請(qǐng)求資源的方法
這篇文章主要介紹了java實(shí)現(xiàn)HttpClient異步請(qǐng)求資源的方法,實(shí)例分析了java基于http協(xié)議實(shí)現(xiàn)異步請(qǐng)求的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07Java Collections.EMPTY_LIST與Collections.emptyList()的區(qū)別
這篇文章主要介紹了Java Collections.EMPTY_LIST與Collections.emptyList()的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11