服務配置現狀
配置文件是我們再熟悉不過的,在微服務系統中,每個微服務不僅僅只有代碼,還需要連接其他資源,例如數據庫的配置或功能性的開關 MySQL、Redis 、Security 等相關的配置。除了項目運行的基礎配置之外,還有一些配置是與我們業務有關係的,比如說七牛存儲、短信和郵件相關,或者一些業務上的開關。
但是隨着微服務系統的不斷迭代,整個微服務系統可能會成爲一個網狀結構,這個時候就要考慮整個微服務系統的擴展性、伸縮性、耦合性等等。其中一個很重要的環節就是配置管理的問題。
常規配置管理解決方案缺點
- 硬編碼(需要修改代碼、繁瑣、風險大)
- properties 或者 yml(集羣環境下需要替換和重啓)
- xml(重新打包和重啓)
爲什麼使用 Spring Cloud Config
由於常規配置管理有很大的缺點,所以採用 Spring Cloud Config 集中式的配置中心來管理每個服務的配置信息。
Spring Cloud Config 在微服務分佈式系統中,採用 Server 服務端和 Client 客戶端的方式來提供可擴展的配置服務。服務端提供配置文件的存儲,以接口的形式將配置文件的內容提供出去;客戶端通過接口獲取數據、並依據此數據初始化自己的應用。
配置中心負責管理所有服務的各種環境配置文件。
配置中心默認採用 Git
的方式存儲配置文件,因此我們可以很容易的部署和修改,有助於環境配置進行版本管理。
Spring Cloud Config 解決了什麼問題
Spring Cloud Config 解決了微服務配置的中心化、版本控制、平臺獨立、語言獨立等問題。其特性如下:
- 提供服務端和客戶端支持(Spring Cloud Config Server 和 Spring Cloud Config Client)
- 集中式管理分佈式環境下的應用部署
- 屬性值的加密和解密(對稱加密和非對稱加密)
- 基於 Spring 環境,無縫與 Spring 應用集成
- 可用於任何語言開發的程序
- 默認實現基於 Git ,可以進行版本管理
接下來,我們主要從以下幾塊來講一下 Config 的使用。
- 基礎版的配置中心(不集成 Eureka)
- 集成 Eureka 版的高可用配置中心
- 基於 Actuator 實現配置的自動刷新
- 配置中心屬性值的加密和解密(對稱加密和非對稱加密)
- 基於 Spring Cloud Bus 實現配置的自動刷新
- 配置中心用戶安全認證
環境準備
項目
config-demo
聚合工程。SpringBoot 2.2.4.RELEASE
、Spring Cloud Hoxton.SR1
。
eureka-server
:註冊中心(用於集成 Eureka 版的配置中心)eureka-server02
:註冊中心(用於集成 Eureka 版的配置中心)order-service
:訂單服務(用於集成 Eureka 版的配置中心)
倉庫
config-repo
倉庫。
Repository name
:倉庫名稱Description(可選)
:倉庫描述介紹Public,Private
:倉庫權限(公開共享,私有或指定合作者)Initialize this repository with a README
:添加一個 README.mdAdd .gitignore
:不需要進行版本管理的文件類型,生成對應文件.gitignore
Add a license
:證書類型,生成對應文件LICENSE
配置文件
不同環境的配置文件,上傳至 config-repo
倉庫。
配置文件的名稱不是亂起的,例如
config-client-dev.yml
和config-client-prod.yml
這兩個文件是同一個項目的不同環境,項目名稱爲config-client
, 一個對應開發環境,一個對應正式環境。test
表示測試環境。
config-client.yml
server:
port: 7777 # 端口
spring:
application:
name: config-client # 應用名稱
# 自定義配置
name: config-client-default
config-client-dev.yml
server:
port: 7778 # 端口
spring:
application:
name: config-client # 應用名稱
# 自定義配置
name: config-client-dev
config-client-test.yml
server:
port: 7779 # 端口
spring:
application:
name: config-client # 應用名稱
# 自定義配置
name: config-client-test
config-client-prod.yml
server:
port: 7780 # 端口
spring:
application:
name: config-client # 應用名稱
# 自定義配置
name: config-client-prod
入門案例
入門案例講解:基礎版的配置中心(不集成 Eureka)
官方文檔:https://cloud.spring.io/spring-cloud-static/spring-cloud-config/2.2.2.RELEASE/reference/html/
創建服務端
點擊鏈接觀看:Config 入門案例創建服務端視頻(獲取更多請關注公衆號「哈嘍沃德先生」)
在 config-demo
父工程下創建子項目 config-server
。
添加依賴
添加 spring-cloud-config-server
依賴,完整 pom.xml
文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>config-server</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 繼承父依賴 -->
<parent>
<groupId>com.example</groupId>
<artifactId>config-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 項目依賴 -->
<dependencies>
<!-- spring cloud config server 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- spring boot test 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
配置文件
server:
port: 8888 # 端口
spring:
application:
name: config-server # 應用名稱
cloud:
config:
server:
git:
uri: https://github.com/imrhelloworld/config-repo # 配置文件所在倉庫地址
#username: # Github 等產品的登錄賬號
#password: # Github 等產品的登錄密碼
#default-label: master # 配置文件分支
#search-paths: # 配置文件所在根目錄
啓動類
啓動類添加 @EnableConfigServer
註解。
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
// 配置中心服務端註解
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
訪問規則
Spring Cloud Config 有一套訪問規則,我們通過這套規則在瀏覽器上直接訪問即可。
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
{application}
:應用名稱(目標服務名稱){profile}
:獲取指定環境配置,項目有開發環境、測試環境、生產環境,對應到配置文件就是以 application-{profile}.yml 加以區分,例如 application-dev.yml、application-test.yml、application-prod.yml。默認值爲 default。{label}
:表示 git 分支,默認是 master 分支,如果項目是以分支做區分也是可以的,那就可以通過不同的 label 來控制訪問不同的配置文件。
測試
http://localhost:8888/config-client/default
http://localhost:8888/config-client/dev/master
http://localhost:8888/config-client-test.yml
http://localhost:8888/master/config-client-prod.yml
訪問以上地址,如果可以正常返回數據,說明配置中心服務端一切正常。
創建客戶端
點擊鏈接觀看:Config 入門案例創建客戶端視頻(獲取更多請關注公衆號「哈嘍沃德先生」)
在 config-demo
父工程下創建子項目 config-client
。
添加依賴
添加 spring-cloud-starter-config
依賴,完整 pom.xml
文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>config-client</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 繼承父依賴 -->
<parent>
<groupId>com.example</groupId>
<artifactId>config-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 項目依賴 -->
<dependencies>
<!-- spring cloud starter config 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- spring boot web 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring boot test 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
配置文件
客戶端配置文件名稱必須叫 bootstrap.yml
spring:
cloud:
config:
name: config-client # 配置文件名稱,對應 git 倉庫中配置文件前半部分
uri: http://localhost:8888 # config-server 服務端地址
label: master # git 分支
profile: default # 指定環境
控制層
添加一個 RestController 用於測試獲取配置文件信息。
package com.example.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigController {
@Value("${name}")
private String name;
@GetMapping("/name")
public String getName() {
return name;
}
}
啓動類
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
}
測試
訪問:http://localhost:7777/name 結果如下:
修改配置文件爲 dev
環境:
spring:
cloud:
config:
name: config-client # 應用名稱,對應 git 倉庫中配置文件前半部分
uri: http://localhost:8888 # config-server 服務端地址
label: master # git 分支
profile: dev # 指定環境
訪問:http://localhost:7778/name 結果如下:
Spring Cloud Config 高可用
以上講了 Spring Cloud Config 最基礎的用法,如果我們的項目中使用了 Eureka 作爲服務註冊發現中心,那麼 Spring Cloud Config 也應該註冊到 Eureka,方便其他服務使用,並且可以註冊多個配置中心服務端,實現高可用。
接下來就集成 Spring Cloud Config 到 Eureka。關於 Eureka 的相關知識大家可翻閱我的歷史文章進行學習。
添加配置文件
在 Github 倉庫中增加配置文件。
order-service-dev.yml
server:
port: 9090 # 端口
spring:
application:
name: order-service # 應用名稱
# 配置 Eureka Server 註冊中心
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 設置服務註冊中心地址
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
# 自定義配置
name: order-service-dev
order-service-prod.yml
server:
port: 9091 # 端口
spring:
application:
name: order-service # 應用名稱
# 配置 Eureka Server 註冊中心
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 設置服務註冊中心地址
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
# 自定義配置
name: order-service-prod
整合註冊中心
案例已經給大家準備好了,無需創建註冊中心直接使用即可,爲了清楚,把依賴和配置信息給大家貼出來。
依賴
eureka-server
和 eureka-server02
核心依賴部分一致。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>eureka-server</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 繼承父依賴 -->
<parent>
<groupId>com.example</groupId>
<artifactId>config-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 項目依賴 -->
<dependencies>
<!-- netflix eureka server 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- spring boot web 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring boot test 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
配置文件
eureka-server
的 application.yml
server:
port: 8761 # 端口
spring:
application:
name: eureka-server # 應用名稱(集羣下相同)
# 配置 Eureka Server 註冊中心
eureka:
instance:
hostname: eureka01 # 主機名,不配置的時候將根據操作系統的主機名來獲取
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
# 設置服務註冊中心地址,指向另一個註冊中心
service-url: # 註冊中心對外暴露的註冊地址
defaultZone: http://localhost:8762/eureka/
eureka-server02
的 application.yml
server:
port: 8762 # 端口
spring:
application:
name: eureka-server # 應用名稱(集羣下相同)
# 配置 Eureka Server 註冊中心
eureka:
instance:
hostname: eureka02 # 主機名,不配置的時候將根據操作系統的主機名來獲取
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
# 設置服務註冊中心地址,指向另一個註冊中心
service-url: # 註冊中心對外暴露的註冊地址
defaultZone: http://localhost:8761/eureka/
啓動類
eureka-server
和 eureka-server02
啓動類核心代碼一致。
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
// 開啓 EurekaServer 註解
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
Spring Cloud Config 服務端
服務端和基礎版的配置中心相比多了 Eureka 的配置,其他地方都是一樣的。
config-server
服務端構建完成以後再復刻一個 config-server02
實現高可用。
依賴
config-server
和 config-server02
核心依賴部分一致。注意是 spring-cloud-config-server
依賴。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>config-server</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 繼承父依賴 -->
<parent>
<groupId>com.example</groupId>
<artifactId>config-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 項目依賴 -->
<dependencies>
<!-- spring cloud config server 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- netflix eureka client 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- spring boot test 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
配置文件
config-server
的 application.yml
server:
port: 8888 # 端口
spring:
application:
name: config-server # 應用名稱
cloud:
config:
server:
git:
uri: https://github.com/imrhelloworld/config-repo # 配置文件所在倉庫地址
#username: # Github 等產品的登錄賬號
#password: # Github 等產品的登錄密碼
#default-label: master # 配置文件分支
#search-paths: # 配置文件所在根目錄
# 配置 Eureka Server 註冊中心
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 設置服務註冊中心地址
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
config-server02
的 application.yml
server:
port: 8889 # 端口
spring:
application:
name: config-server # 應用名稱
cloud:
config:
server:
git:
uri: https://github.com/imrhelloworld/config-repo # 配置文件所在倉庫地址
#username: # Github 等產品的登錄賬號
#password: # Github 等產品的登錄密碼
#default-label: master # 配置文件分支
#search-paths: # 配置文件所在根目錄
# 配置 Eureka Server 註冊中心
eureka:
instance:
prefer-ip-address: true # 是否使用 ip 地址註冊
instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
client:
service-url: # 設置服務註冊中心地址
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
啓動類
config-server
和 config-server02
啓動類核心代碼一致。
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
// 開啓 EurekaClient 註解,當前版本如果配置了 Eureka 註冊中心,默認會開啓該註解
//@EnableEurekaClient
// 配置中心服務端註解
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
Spring Cloud Config 客戶端
客戶端加入 Eureka 以後,就不用直接和配置中心服務端打交道了,而是通過 Eureka 來訪問。
依賴
order-service
的 pom.xml。注意是 spring-cloud-starter-config
依賴。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>order-service</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 繼承父依賴 -->
<parent>
<groupId>com.example</groupId>
<artifactId>config-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 項目依賴 -->
<dependencies>
<!-- spring boot web 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- netflix eureka client 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- spring cloud starter config 依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- spring boot test 依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
配置文件
order-service
的 bootstrap.yml
spring:
cloud:
config:
name: order-service # 配置文件名稱,對應 git 倉庫中配置文件前半部分
label: master # git 分支
profile: dev # 指定環境
discovery:
enabled: true # 開啓
service-id: config-server # 指定配置中心服務端的 service-id
控制層
添加一個 RestController 用於測試獲取配置文件信息。
package com.example.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigController {
@Value("${name}")
private String name;
@GetMapping("/name")
public String getName() {
return name;
}
}
啓動類
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// 開啓 EurekaClient 註解,當前版本如果配置了 Eureka 註冊中心,默認會開啓該註解
//@EnableEurekaClient
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
測試
啓動註冊中心 eureka-server
和 eureka-server02
。
啓動配置中心服務端 config-server
。
啓動配置中心客戶端 order-service
。
當前環境在 Eureka UI
界面中如下:
訪問:http://localhost:9090/name 結果如下:
配置中心工作原理
開發人員將配置文件存儲至 Git 遠程倉庫,或後期對 Git 遠程倉庫的文件進行修改。如果遠程倉庫發生了版本改變,Config Server 會將 Git 遠程倉庫中的文件同步至本地倉庫中。大家仔細觀察 Config Server 的控制檯可以看到類似如下信息。
[nio-8888-exec-1] o.s.c.c.s.e.NativeEnvironmentRepository : Adding property source: file:/C:/Users/MRHELL~1/AppData/Local/Temp/config-repo-17506367621853740906/order-service-dev.yml
根據控制檯信息打開對應的本地目錄,會發現 Git 遠程倉庫中的文件已同步至本地倉庫中。
爲什麼要這麼做呢?因爲我們要考慮網絡波動的情況下,無法訪問遠程倉庫的問題。
下一篇我們講解 Config 如何實現配置中心自動刷新,記得關注噢~
本文采用 知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協議
。
大家可以通過 分類
查看更多關於 Spring Cloud
的文章。
🤗 您的點贊
和轉發
是對我最大的支持。
📢 掃碼關注 哈嘍沃德先生
「文檔 + 視頻」每篇文章都配有專門視頻講解,學習更輕鬆噢 ~