Spring Cloud Config Server/Client結合Git
前言
Spring Cloud Config 中心化配置,本文將使用Spring Cloud Config 並結合Git掛在雲配置,Git倉庫選擇的gitee,具體用意跟實現理由等等理論化就不說了。進入主題,第一步是創建gitee倉庫,並在倉庫裏新建一個配置文件jamtest-client.yml;第二步是新建工程SpringCloud-config-server;第三步是新建工程SpringCloud-config-client。
1. 創建gitee倉庫
這裏新建了個名爲spring-cloud-demo的倉庫,根目錄下,重點關注 jamtest-client.yml。
倉庫裏實際上有三個yml配置文件,jamtest-dev.yml和jamtest-prod.yml其實只是從一個多環境切換的yml分成了幾個文件而已,可以忽略。
#jamtest-client.yml
spring:
profiles:
active: dev
---
#開發環境端口8001
server:
port: 8001
spring:
profiles: dev
---
#生產環境端口8002
server:
port: 8002
spring:
profiles: prod
至此,配置倉庫建立完成,需要記錄下該倉庫的git地址。
2. 創建Spring Cloud config-server工程
首先需要添加spinrg-cloud-config-server的依賴,pom.xml的關鍵內容
<!--pom.xml-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>1.3.1.RELEASE</version>
</dependency>
修改application.yml文件
server:
port: 8888
spring:
cloud:
config:
server: #聲明是sping cloud config server
git:
uri: https://gitee.com/YGJam/spring-cloud-demo.git #第一步創建的gitee倉庫的uri
#searchPaths 文件目錄
#username 由於我第一步創建的是public倉庫,不需要再寫用戶名和密碼,未嘗試private
#password 有興趣可以試試看
關鍵配置部分:spring.cloud.config.server和spring.cloud.config.server.git.uri以及spring.cloud.config.server.git.uri.searchPaths屬性。由於是直接放在根目錄,所以只需uri,如果是放在根目錄下的某個文件夾內,可以添加 searchPaths:文件夾名。
修改啓動類ConfigServerApplication.java
@SpringBootApplication
@EnableConfigServer //開啓配置
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
此時Spring Cloud Config Server已經搭建完成,而它的端口8888已經可以拉取配置信息,具體如下,通過postman發送GET請求 ip:port/[文件名]-[激活的配置項].yml ,可以獲取到對應的配置信息
我的倉庫中保留了之前的寫的兩份把yml配置分開的文件,也可以進行拉取。
至此,Spring Cloud Config Server已經配置完成,所寫的配置信息可以選擇多環境配置集中在一個yml文件中 如jamtest-client.yml,裏面在通過profiles來區分環境,或者直接分開多開配置文件 如jamtest-prod,jamtest-dev。
3.創建Spring Cloud config-client工程
這裏所說的spring cloud config client 通俗來講就是通過spring cloud config 這樣的中心配置來獲取自身配置信息的任意一個客戶端(它可以是一個eureka、也可以是一個comsumer)。
首先,肯定還是pom.xml的依賴
<!--pom.xml-->
<dependency> <!--spring web,後續測試用到-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency> <!--監視器功能依賴,後續動態刷新時需要用到,建議添加-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>1.3.1.RELEASE</version>
</dependency>
配置bootstrap.yml,bootstrap.yml跟application.yml的功能類似,但是級別不一樣,理論上來說,前者是系統級別的,一般不做更改的配置信息會放在bootstrap.yml裏,不會被覆蓋,而後者是用戶應用級別的,存放的是可以更改的配置信息。(甚至可以不配置application.yml)
#bootstrap.yml
spring:
application:
name: cloud-config-client-test
cloud:
config:
name: jamtest-client #選擇的配置文件
profile: prod #當前激活的配置環境,常寫的有prod、dev等
uri: http://127.0.0.1:8888 # Config server的uri
label: master #選擇的分支
management:
security:
enabled: false # 動態更新配置所需要的配置
關鍵配置部分:
- spring.cloud.config.name 指定選擇的配置文件名 本倉庫中可以選擇 jamtest-clinet 或者 jamtest
- spring.cloud.config.profile 當前激活的配置環境 本倉庫可以選擇 prod 或者 dev
- spring.cloud.config.uri 配置服務器的uri,也即 spring cloud config server的訪問地址
- spring.cloud.config.label 選擇的分支
最下面的managment那一系列是爲了能夠動態刷新配置信息,spring boot 1.5x+會默認爲true(網上是這麼說的)
本次只配置了bootstrap.yml,沒有配置application.yml,監聽端口也沒有出現在這裏的配置文件中,而把監聽端口放在了git的遠端倉庫。
ConfigClientApplication.java不需要額外配置註解啥的,默認就可以
爲了方便測試,寫了一個controller來進行訪問。
// TestController
@RestController
@RefreshScope //開啓實時更新功能
public class TestController {
@Value("${server.port}")
private String port;
@GetMapping("/test")
public String test(){
return port;
}
}
在bootstrap.yml的配置中 拉去的是jamtest-client-prod的配置內容,端口應該爲8002,如果正確,啓動這兩個程序後,可以訪問 localhost:8002/test ,並且會返回當前的端口。
4.驗證測試,進行動態刷新配置
先啓動SpringCloud-config-server,然後再啓動SpringCloud-config-client,測試:
得到了想要的結果,可以通過更改 client工程裏的bootstrap.yml中的profile進行環境的切換,或者在打jar包時來指定環境進行更改。
**實時動態刷新:**springboot程序只會在啓動時讀取它們的配置屬性,所以如果我們的gitee倉庫中的配置文件發生了變化,在本次運行時,是不會被更新的,如果要進行動態的刷新,就需要@Refresh註解,並訪問 /refresh 斷點,這樣可以讓SpringBoot程序重新讀取。
在啓動程序後,手動修改gitee倉庫中jamtest-client-prod的端口信息爲8003。
首先通過SpringCloud config-server來查看配置信息,會發現配置信息在服務器上已經發生了變化。
然而在它的客戶端,配置信息並沒有發送變化,監聽的端口依然是8002,可以嘗試請求 localhost:8002/test ,它的返回值結果依然是8002。而如上所說,可以通過訪問 /refresh端點,所以要執行刷新操作,可以訪問 ip:port/refresh,這裏的ip仍然是8002。
**注意這是一個POST操作!**我猜測它的返回是發生變化的配置信息(具體我也沒驗證,但是從結果上來說 是的)。
最後來看一下最終的結果,這個結果是我最初比較意外的,發現刷新之後,通過 server.prot裏 獲取到的端口值,確實是更新後的8003,而實際程序運行監聽的端口 依然是最初啓動時所監聽的8002,而我最初設想的刷新後的客戶端服務路徑應該是 localhost:8003/test 有較大的偏差 。
但仔細一想,似乎確實也應該是這樣,(以下結論爲個人的猜想與推測,可能存在有誤,會進一步去請教業內大佬,如果持有不同意見或有所瞭解,請評論指正)。
5.結論
這裏的刷新新屬性僅僅是刷新了客戶端程序中 yml配置文件中的值,而對於當前正在運行的客戶端服務實例,它的監聽端口依然會是最初啓動時的監聽端口,雖然這個程序的yml配置文件發生了變化,但程序並未重啓,端口沒有改變,而@Value操作是從yml文件中讀取server.port 此時讀取到的是最新的端口值。所以會出現 訪問端口是8002而server.port返回值是8003的情況
存留疑惑:
- 如果想要讓運行中的服務實例真正的做到“最新”,是否一定要重啓該服務,還是有其他的手段?
- 我只測試了端口的變化,而如果配置信息是數據庫連接信息,那麼refresh後 是會重新定位到更改後的數據庫 還是仍然原先的數據庫
- 熱部署應該是可以解決以上問題?