title: springcloud系列之配置中心
date: 2021-06-03 12:00:30
tags:
- [配置中心]
- [config]
categories:
- [springcloud]
permalink: zxh
prefix: springcloud
背景
有多少次因爲配置文件忘記修改導致重新發布
有多少次因爲無法實時修改配置導致重新發布
有多少次同一個配置在不同項目需要重複修改
有多少次因爲配置導致項目啓動失敗!!!
配置服務中心
- 面對上面種種的問題
springcloud
爲我們提供一種解決方案---Springcloud Config
它爲分佈式微服務提供了集中化的外部配置支持,配置服務器爲微服務下所有環境提供配置中心 Springcloud Config
分爲服務端和客戶端、服務端就是本節介紹的對象。而客戶端就是嵌入在各個微服務中和服務端進行交互的從而實現配置的動態獲取
pom
- 還是一樣的味道我們通過
framework-root
框架來實現我們config中心,首先繼承framework-root
然後在pom中添加如下座標
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-config-server</artifactid>
</dependency>
application.yml
- 除了一些基本的參數設定以外我們需要指定config拉取的倉庫即git相關信息
server:
port: 8070
spring:
application:
name: config-server
cloud.config.server.git:
uri: https://gitee.com/zxhTom/spring-cloud-demo
searchPaths: helloworldconfig
啓動類
@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class,args);
}
}
測試
- 你沒看錯!就是這簡單或者說還是之前的配方。我們只需要引包、配置、啓動即可!這就是spring的強大之處或者說是
springboot
的開箱即用的強大之處 - 我們訪問
http://localhost:8070/master/config-server-dev.properties
就會將https://gitee.com/zxhTom/spring-cloud-demo
項目下master分支下的helloworldconfig
文件夾下的config-server-dev.properties
文件讀取出來! - 請注意下,筆者的
config
倉庫後續會有變動。最終讀者的演示情況和筆者這裏略有不同!!!
路徑規則
- 上面我們已經可以通過接口的形式訪問到我們的配置文件了。但是那只是其中一種方式我們換個接口同樣可以訪問到
http://localhost:8070/config-server-dev.yml
。那麼config的代理訪問肯定是按照一定規律來的。我們訪問官網,官網已經幫我們整理好了
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
- 咋一看,心裏萬馬奔騰這是啥玩意呀。再仔細看看你會發現官網總結的太到位了。首先官網整理出的是三種訪問格式:
resultful
、yml
、properties
。當我們的接口滿足其中一種格式的時候就會被config
解析出來並有對應變量管理。
- 爲了充分演示出效果,小哲這裏新建了幾個配置文件。當我們訪問如下接口時會出現哪幾種情況
http://localhost:8070/config/server-dev
. - 按照我們上面的格式進行匹配,首先是
resultful
結構的,那麼就只有一種匹配方式得出application=config;profile=server-dev,label=null
。label是可填的默認是master。
- 最終我們可以看到我們分析是沒有問題,其中多處一個
version
字段,這個筆者猜測是git commitId
,因爲我發現和提交記錄一樣。 而對應的配置文件就是propertySources
裏的文件。細心的朋友一定會發現這裏爲什麼是個數組呢?這裏筆者在官網上沒有找到說明但是經過測試筆者這裏整理出springcloud config
映射規則
//後綴包括兩種 。 回去找{label}分支下如下格式的文件
{application}/{profile}.[properties|yml]
{application}.[properties|yml]
- 另外兩種方式和
resultful
差不多,只不過他返回的信息時精簡版的。只返回配置文件中內容的並集。這裏需要注意相同內容取前者,那麼誰先誰後呢?這就需要我們resultful
格式接口告訴我們了。
- 記住這個時候我們訪問
http://localhost:8070/config-server.properties
。 然後通過resultful
風格來確定是來源哪裏.這裏在強調下上面hello爲什麼是yml
。還記得上面我提到在這麼多文件中如果存在相同的配置會優先去首位的。這是什麼意思呢? - 我們通過
resultful
可以看出來會讀取三個文件的配置分別是config-server.properties
、config-server.yml
、config.properties
。
- 我們在分別看下這三個文件中的內容,hello這個key出現在兩個文件中。然後在
resultful
接口我們可以看出config-server.yml
排在config.properties
前面,所以我們通過文件後綴方式訪問到的數據配置hello=yml
。
配置讀取客戶端
- 上面我們也提到了關於
config
存在兩個角色,config
中心是用來統一爲微服務提供服務的,剩下的就是嵌入在微服務中的。在配置微服務的config
客戶端之前我們先來梳理下springboot
的一個注意點。 springboot
的配置文件除了在加載順序有不同之外,還有一點是文件名的區別。在springboot
中其實存在兩種配置文件名稱;我們常用的是application開頭的配置文件(application.yml
和application.properties
)。springcloud
程序會創建一個bootstrap
上下文同時他也是application上下文的父類!它負責從外部源加載配置屬性,並解密本地外部配置文件中的屬性。這兩個上下文共享一個Environment,它是任何Spring應用程序的外部屬性的來源。在springcloud
中bootstrap類型的配置文件優先級最高所以不需要擔心會被本地的配置所覆蓋。- 我們客戶端想要讀取
config-server
中心的配置數據我們就需要在bootstrap
配置文件中配置。
bootstrap.yml
zxhtom: hello-zxhtom
spring:
cloud:
config:
label: master
name: config-server
profile: dev //這裏和config-server解析不一樣的是,他將訪問master分支下的config-server-dev.yml或者properties文件
uri: http://localhost:8070
application.yml
zxhtom: hello-zxhtom2
server:
port: 80
tomcat:
max-threads: 10
pom
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-config</artifactid>
</dependency>
測試
- 首先引入
pom
包這裏大家應該都沒有問題,其次我們在application.yml
和bootstrap.yml
兩個配置文件中配置相同的東西。這個時候在bootstrap中不配置config
東西。此時我們訪問zxhtom
參數得到的結果是application中的。當我們將config
配置加進來之後我們訪問到的是git遠程倉庫的東西。關於演示筆者這裏就不演示了。因爲上面配置完成之後我們只需要寫個接口獲取參數就可以了。
小瑕疵
-
但是存在一個小瑕疵,當我們遠程倉庫配置修改後我們的服務也需要跟着修改!這好坑啊,感情玩了半天我還在原地打轉啊。除了解決多模塊相同配置重複修改的問題,重啓的問題還是沒能解決。難道我們就只能如此了嗎?
-
上面我們已經實現
config-server
來讀取遠程倉庫配置了。也實現了客戶端通過config-server
讀取遠程配置了。但是當我們修改git遠程倉庫上配置時,我們的config-server
會實時的修改配置值,客戶端確無法實時更新!解決辦法就是重啓。
動態刷新
- 發現問題才能不斷進步當然前提你得承認問題!這是一個偉大的哲學家說的(我自己) 。
- 首先我們需要引入
actuator
模塊,這個我們在講解hystrix
模塊的時候在父項目root中引入了。當時筆者一直出了在高版本中actuator中需要加入actuator前綴。 - 然後我們在獲取配置的接口類上添加
@RefreshScope
。 記住這裏一定要在這裏加哦!!! - 好了,到這裏我們就解決了,現在啓動我們的config客戶端,在這裏我們是
order
模塊。啓動之後通過http://localhost/order/config/getConfig
獲取zxhtom這個值。
仍然不足
- 上面我們基於
actuator
實現了動態刷新,但是這個動態刷新並不是自動刷新還是需要我們認爲參與。實際項目生產使用中會有很多個微服務充電config-client角色。那麼我們每次更新git倉庫內容時是不是需要誒個調用接口呢?這顯然是不行的。我也說了存在問題才能優化。那麼我們該如何解決
奇技淫巧
脫離git
- 在
config-server
中我們通過spring.cloud.config.server.git.uri
中指定git遠程倉庫。如果我們在內網環境開發而且內網中我們沒有自己搭建git服務呢。我們可以配置本地地址也可以實現讀取指定外部倉庫的。
spring.cloud.config.server.git.uri=file://xxxxxx/repository
多倉庫
spring.cloud.config.server.git:
uri: https://gitee.com/zxhTom/spring-cloud-demo
searchPaths: helloworldconfig
repos:
dev:
pattern: dev/*
uri: file:///D:\test\repository\spring-cloud-demo
searchPaths: helloworldconfig
- 上述配置
spring.cloud.config.server.git.uri
是默認的倉庫配置。然後根據repos
來進行多倉庫的配置。repos
下跟了多少個就說明是多少個環境配置。比如我們上面的配置repos
下只有dev
一個配置,這個dev
就是我們用於dev
的環境。他的匹配模式是任何已dev
開頭的都將使用dev
這個配置的倉庫來進行我們上面匹配規則分析。
添加權限
-
如果你的公司沒有單獨部署git。如果你使用的就是
github
這種公網性質。那麼將我們項目中的配置放在這種地方是不是有點不安全呢?你的所有的服務的密碼都被公開了。這樣是極度不安全。那麼我們要麼自己單獨部署git。要麼將配置文件這個項目設置成私有 -
項目配置成私有我們config-server所在的服務可以通過ssh方式進行配置項目uri 。
-
spring: cloud: config: server: git: username: xxxx password: xxxx
-
我們也可以通過如上配置方式將我們項目的用戶名和密碼配置,然後在通過http方式進行訪問。這樣也是可以的。
指定本地倉庫位置
- 當我們通過接口訪問獲取遠程倉庫配置信息的時候,實際上config幫我們將遠程倉庫的文件拉取到本地路徑上了。這個我們通過觀察日誌就可以看得出來。
- 可以證實我們沒訪問一次接口
config都會刷新本地文件庫的。但是本地文件存儲的位置其實是不固定的,項目每次啓動當前項目所在的目錄都會發生隨機改變。文件路徑爲
config-repo-隨機id。會出現這麼一種情況當我們重啓的時候git掛了這個時候我們將無法獲取但是因爲隨機id的原因我們將獲取不到配置信息了。所以
config` 可以讓我們指定這個路勁。
spring.cloud.config.server.git.basedir: xxxxx
分模塊讀取配置
- 實際分佈式項目中我們會有很多模塊,如果我們都將放在同一層級的話會顯得很多。這用並不是不能使用但是爲了方便管理我們還是希望能夠進行分類管理不同的服務請求過來進不同文件中進行匹配。
spring.cloud.config.server.git.searchPaths: '{application}'
- 而application就是我們上文提到的通過地址分析中得到的那個application 。注意這裏一定要加引號
總結
springcloud config
模塊極大的簡化了我們微服務中重複配置的問題,默認使用的git來實現公共服務的獲取的當然他也是支持svn
,關於svn
的整合呢筆者這裏沒有指出因爲現在使用svn
的公司應該很少了。如果非要使用svn
的話也很簡單。將uri
地址換成svn
的就可以了。前提引入如下包
<dependency>
<groupid>org.tmatesoft.svnkit</groupid>
<artifactid>svnkit</artifactid>
<version>1.8.10</version>
</dependency>