最近有項(xiàng)目組同學(xué)問(wèn)到為什么自己配置了nacos,但配置不生效?我簡(jiǎn)單看了下,發(fā)現(xiàn)問(wèn)題出在相關(guān)配置的優(yōu)先級(jí)模式不同。
spring-boot項(xiàng)目,有bootstrap、application兩個(gè)配置文件,結(jié)合profile,和支持的文件格式properties、yaml,已經(jīng)有6個(gè)配置文件了。然后使用了spring-cloud-starter-alibaba-nacos-config 后,又提供了三級(jí)配置。這些配置之間的組合關(guān)系,將在無(wú)形中影響配置的效果。很多同學(xué)只知道其中的一種,因此在無(wú)意識(shí)引入兩種或以上的配置后,就會(huì)發(fā)現(xiàn)有奇怪的配置不生效問(wèn)題發(fā)生。
1. bootstrap.yaml
spring-boot項(xiàng)目依賴(lài)bootstrap.yml 用于應(yīng)用程序上下文的引導(dǎo)階段,由父Spring ApplicationContext加載,其工作的階段為父ApplicationContext 被加載到使用application.yml的之前。也就是說(shuō) bootstrap 加載優(yōu)先于 applicaton。
bootstrap 主要用于從額外的資源來(lái)加載配置信息,還可以在本地外部配置文件中解密屬性。這兩個(gè)上下文共用一個(gè)環(huán)境,它是任何Spring應(yīng)用程序的外部屬性的來(lái)源。bootstrap 里面的屬性會(huì)優(yōu)先加載,它們默認(rèn)也不能被本地相同配置覆蓋。
bootstrap 配置文件有以下幾個(gè)應(yīng)用場(chǎng)景:
- 使用 Spring Cloud Config 配置中心時(shí),這時(shí)需要在 bootstrap 配置文件中添加連接到配置中心的配置屬性來(lái)加載外部配置中心的配置信息;
- 系統(tǒng)級(jí)別的一些參數(shù)配置,這些參數(shù)一般是不會(huì)變動(dòng)的,不能被覆蓋的屬性
- 一些加密/解密的場(chǎng)景;
由于spring-boot支持多種文件格式,所以多種格式之間,其優(yōu)先級(jí)是平等的,只要找到了一個(gè),就會(huì)被使用。一般有:.properties、.yaml、.xml等格式。
2. application.yaml
應(yīng)用級(jí)別的spring-boot配置文件,主要用于 Spring Boot 項(xiàng)目的自動(dòng)化配置,其加載優(yōu)先級(jí)低于bootstrap.yaml。
- spring-boot 默認(rèn)會(huì)從4個(gè)路徑去找 application 配置:
- 按優(yōu)先級(jí),假設(shè)當(dāng)前運(yùn)行目錄為
/,優(yōu)先級(jí)依次為:/config>/>classpath:/config>classpath:/- 同時(shí)出現(xiàn)在上述四個(gè)配置文件中的同名屬性,按優(yōu)先級(jí)的覆蓋低優(yōu)先級(jí)的。
- 分別出現(xiàn)在不同配置文件中的非同名屬性,合并后生效。
- 對(duì)同名但不同后綴名的配置文件,
properties>yaml
- 對(duì)存在profile的場(chǎng)景,指定profile的配置優(yōu)先級(jí)高于無(wú)profile的配置。
- 還可以在啟動(dòng)命令中指定外部配置文件路徑。
可以在啟動(dòng)命令時(shí),通過(guò)
--spring.config.location命令參數(shù)指定用逗號(hào)分割的外部配置文件路徑,該路徑下配置高于一切。
3、spring-cloud-nacos引入的三級(jí)配置文件
nacos作為外部配置服務(wù)器,通過(guò)spring-boot的bootstrap.yaml引入。但nacos本身,也提供了三級(jí)配置體系:主配置(只有一個(gè),但會(huì)按照不同后綴名,去找到相關(guān)配置)、擴(kuò)展配置、共享配置。
三級(jí)配置的優(yōu)先級(jí)如下:主配置 > 擴(kuò)展配置 > 共享配置
3.1 主配置
nacos提供的配置路徑 spring.cloud.nacos.config 下,有一系列的屬性用于定位主配置?;?prefix(默認(rèn)為 ${spring.application.name} 的值)、namespace、group(默認(rèn)為字符串 DEFAULT_GROUP)、file-extension(默認(rèn)為字符串 .properties),按組裝規(guī)則 ${prefix}-${spring.profiles.active}.${file-extension}去找到一個(gè)配置。
spring:
application:
name: ddd-demo-service
cloud:
nacos:
config:
server-addr: nacos-2.nacos-headless.public.svc.cluster.local:8848
namespace: ygjpro-test2
上述配置,意味spring-boot和nacos 將按照如下規(guī)則執(zhí)行:
- 按照規(guī)則
${prefix}-${spring.profiles.active}.${file-extension}來(lái)獲得dataId:ddd-demo-service.properties。因?yàn)椋?/li>
${prefix}:沒(méi)有指定${prefix},取默認(rèn)值${spring.application.name},為字符串ddd-demo-service。spring.profiles.active:沒(méi)有指定spring.profiles.active,取默認(rèn)值空。${file-extension}:沒(méi)有指定${file-extension},取默認(rèn)值字符串.properties
- spring-boot將嘗試去nacos的 ygjpro-test2 表空間,在 DEFAULT_GROUP group 分組下,加載一個(gè)dataId叫做 ddd-demo-service 的配置。
- 如果發(fā)現(xiàn)上述dataId不存在,則繼續(xù)嘗試加載名為 ddd-demo-service 的dataId,該dataId只是前面步驟1中獲得的dataId,去掉
file-extension后綴名。- 如果上述兩個(gè)步驟都沒(méi)有找到dataId,就不再?lài)L試去找主配置了。
在nacos的所有配置中,主配置(存在的情況下)具有最高的優(yōu)先級(jí),其同名配置值不能被擴(kuò)展配置或共享配置中定義的同名屬性所覆蓋。
3.2 共享配置和擴(kuò)展配置
- nacos在配置路徑
spring.cloud.nacos.config.extension-configs下,允許我們指定一個(gè)或多個(gè)額外配置。 - nacos在配置路徑 spring.cloud.nacos.config.shared-configs 下,允許我們指定一個(gè)或多個(gè)共享配置。
上述兩類(lèi)配置都支持三個(gè)屬性:data-id、group(默認(rèn)為字符串 DEFAULT_GROUP)、refresh(默認(rèn)為true)。
3.2.1 共享配置和擴(kuò)展配置的區(qū)別
實(shí)際上,nacos中并未對(duì) extension-configs 和 shared-configs 的差別進(jìn)行詳細(xì)闡述。我們從他們的結(jié)構(gòu),看不出本質(zhì)差別;除了優(yōu)先級(jí)不同以外,也沒(méi)有其他差別。那么,nacos項(xiàng)目組為什么要引入兩個(gè)類(lèi)似的配置呢?我們可以從當(dāng)初該功能的需求(issue)上找到其原始目的。
摘要其核心內(nèi)容如下:
- nacos對(duì)配置的默認(rèn)理念
根據(jù)nacos的默認(rèn)理念:
- namespace區(qū)分環(huán)境:開(kāi)發(fā)環(huán)境、測(cè)試環(huán)境、預(yù)發(fā)布環(huán)境、生產(chǎn)環(huán)境
- group區(qū)分不同應(yīng)用:同一個(gè)環(huán)境內(nèi),不同應(yīng)用的配置,通過(guò)group來(lái)區(qū)分。
- 主配置是應(yīng)用專(zhuān)有的配置。
因此,主配置應(yīng)當(dāng)在dataId上要區(qū)分,同時(shí)最好還要有 group 的區(qū)分,因?yàn)間roup區(qū)分應(yīng)用(雖然dataId上區(qū)分了,不用設(shè)置group也能按應(yīng)用單獨(dú)加載)。
- 要在各應(yīng)用之間共享一個(gè)配置,請(qǐng)使用上面的 shared-configs。
因此按該理念,shared-configs 指定的配置,本來(lái)應(yīng)該是不指定 group的,也就是應(yīng)當(dāng)歸入 DEFAULT_GROUP 這個(gè)公共分組。
- 如果要在特定范圍內(nèi)(比如某個(gè)應(yīng)用上)覆蓋某個(gè)共享dataId上的特定屬性,請(qǐng)使用 extension-configs
比如,其他應(yīng)用的數(shù)據(jù)庫(kù)url,都是一個(gè)固定的url,使用 shared-configs.dataId = mysql 的共享配置。
但其中有一個(gè)應(yīng)用 ddd-demo 是特例,需要為該應(yīng)用配置擴(kuò)展屬性來(lái)覆蓋。所以定義如下擴(kuò)展配置:spring: application: name: ddd-demo-service cloud: nacos: config: server-addr: nacos-2.nacos-headless.public.svc.cluster.local:8848 namespace: ygjpro-test2 group: ddd-demo ...... shared-configs[3]: data-id: mysql.yaml refresh: true ...... extension-configs[3]: data-id: mysql.yaml group: ddd-demo refresh: true
- step1: 我們?cè)趃roup 為 DEFAULT_GROP 的分組內(nèi),創(chuàng)建各應(yīng)用的共享配置dataId為mysql
- step2:我們?cè)趃roup 為 ddd-demo 的分組內(nèi),,創(chuàng)建 ddd-demo 應(yīng)用專(zhuān)有的配置mysql,其中定義的屬性,會(huì)覆蓋上述共享配置中定義的同名屬性。
3.2.2 關(guān)于優(yōu)先級(jí)
- 上述兩類(lèi)配置都是數(shù)組,對(duì)同種配置,數(shù)組元素對(duì)應(yīng)的下標(biāo)越大,優(yōu)先級(jí)越高。也就是排在后面的相同配置,將覆蓋排在前面的同名配置。
比如:
- 同為擴(kuò)展配置,存在如下優(yōu)先級(jí)關(guān)系:
extension-configs[3] > extension-configs[2] > extension-configs[1] > extension-configs[0]- 同為共享配置,存在如下優(yōu)先級(jí)關(guān)系:
shared-configs[3] > shared-configs[2] > shared-configs[1] > shared-configs[0]
- 不同種類(lèi)配置之間,優(yōu)先級(jí)按順序如下:主配置 > 擴(kuò)展配置(extension-configs)> 共享配置(shared-configs)。
3.2.3 在nacos中配置的注意事項(xiàng)
- 主配置
主配置有 ${file-extension} 來(lái)指定文件后綴,因此在根據(jù)規(guī)則生成 dataId時(shí),spring-boot 知道如何去識(shí)別這個(gè)讀取下來(lái)的文件。所以在nacos中配置時(shí),dataId可以帶文件后綴,也可以不要帶文件后綴。
spring-boot 發(fā)現(xiàn)用不帶文件后綴的dataId讀取不到時(shí),會(huì)嘗試去掉文件后綴后的dataId 再去讀取一次。
- 共享配置/擴(kuò)展配置
共享配置和擴(kuò)展配置沒(méi)有 filez-extension 屬性,因此 spring-boot 會(huì)認(rèn)為 dataId 本身已經(jīng)包含了 文件后綴了。如果當(dāng)發(fā)現(xiàn)按照配置中指定的dataId去nacos取回來(lái)的文件沒(méi)有后綴名時(shí),spring-boot將不會(huì)識(shí)別讀取回來(lái)的文件。