前言
在 分布式系統 中,由于服務數量巨多,為了友善 服務配置檔案 的 統一管理 和 實時更新,是以需要 分布式配置中心 元件。
Spring Cloud
提供的 分布式配置中心 元件是
Spring Cloud Config
,它支援将 配置服務 放在配置服務的 記憶體 中(即 本地),也支援放在 遠端
Git
倉庫中。
Spring Cloud Config
提供了兩個角色,其一是
Config Server
,其二是
Config Client
。
正文
1. Config Server從本地讀取配置檔案
建立一個新的
Spring Boot
項目子產品,取名為
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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.github.ostenant.springcloud</groupId>
<artifactId>config-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>config-server</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在應用啟動類上使用 注解
@EnableConfigServer
開啟 配置伺服器。
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
需要在程式的 配置檔案
application.properties
裡面進行如下配置。通過
spring.profile.active=native
來配置
Config Server
從 本地讀取配置,讀取的路徑為
Classpath
下的
shared
目錄。
server:
port: 8769
spring:
application:
name: config-server
profiles:
active: native
cloud:
config:
server:
native:
search-locations: classpath:/shared
在
src/main/resources
目錄下建立
shared
檔案夾,在
shared
檔案夾下建立一個
config-client-dev.yml
檔案。
server:
port: 8762
foo: foo version 1
運作
ConfigServerApplication
的
main()
方法,在
8769
端口啟動
Config Server
應用程式。
2. 建構Config Client
建立一個
Spring Boot
項目子產品,取名為
config-client
,它的
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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.github.ostenant.springcloud</groupId>
<artifactId>config-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>config-client</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在
resources
目錄下建立
bootstrap.yml
檔案,因為
bootstrap
相對于
application
具有 優先的執行順序。
變量
{spring.application.name}
和
{spring.profiles.active}
,兩者使用
“-”
相連,作為
Config Client
向
Config Server
讀取的 配置檔案名。
bootstrap.yml
spring:
application:
name: config-client
cloud:
config:
uri: http://localhost:8769
fail-fast: true # 讀取沒有成功,執行快速失敗
profiles:
active: dev
配置一個接口,用于測試 讀取配置檔案 的
foo
變量,并通過
API
接口傳回用戶端。
@RestController
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
@Value("${foo}")
private String foo;
@RequestMapping(value = "/foo")
public String foo(){
return foo;
}
}
啟動
config-client
應用程式,通路
http://localhost:8762/foo
,服務端的響應資料如下:
foo version 1
可見
config-client
成功地從
config-server
項目的
shared
本地檔案目錄 讀取到 配置檔案
config-client-dev.yml
中的
foo
變量。
3. Config Server從遠端Git倉庫讀取配置檔案
修改
config-server
的配置檔案
application.yml
,代碼如下.
server:
port: 8769
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://coding.net/ostenant/config-repo
search-paths: test
username: [email protected]
password: xxxx
label: master
如果
Git
倉庫為 公開倉庫,可以不填寫 使用者名 和 密碼;如果是 私有倉庫 則需要填寫,本例子配置了一個 私有倉庫。
配置 | 解釋 |
---|---|
spring.cloud.config.server.git.uri | 配置git倉庫位址 |
spring.cloud.config.server.git.searchPaths | 配置倉庫路徑 |
spring.cloud.config.label | 配置倉庫的分支 |
spring.cloud.config.server.git.username | 通路git倉庫的使用者名 |
spring.cloud.config.server.git.password | 通路git倉庫的使用者密碼 |
遠端倉庫
https://coding.net/ostenant/config-repo
中有個 名為
config-client-dev.properties
的 配置檔案,裡面配置有一個屬性:
foo = foo version 2
重新啟動應用程式
config-server
和
config-client
,再次通路
http://localhost:8762/foo
,服務端的響應資料如下:
foo version 2
可見,
config-server
從遠端
Git
倉庫讀取了 配置檔案,進一步
config-client
從
config-server
讀取了相關的 配置屬性。
4. 建構高可用的Config Server
将 配置中心
config-server
做成一個 微服務,并且将其 叢集化,進而實作 高可用。
4.1. 改造Config Server
在
Config Server
中引入
Eureka
用戶端的 起步依賴
spring-cloud-starter-eureka
。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
在應用的 啟動類 上加上 注解
@EnableEurekaClient
,将
Config Server
注冊到
Eureka Server
上面。
在配置檔案
application.yml
加入 服務注冊位址:
eureka:
client:
service-url:
defaultZone: http://locahost:8761/eureka/
4.2. 改造Config Client
同樣的在
Config Client
中引入
Eureka
用戶端的 起步依賴
spring-cloud-starter-eureka
。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
在應用的 啟動類 上加上 注解
@EnableEurekaClient
,将
Config Client
注冊到
Eureka Server
上面。
在配置檔案
application.yml
加入 服務注冊位址:
eureka:
client:
service-url:
defaultZone: http://locahost:8761/eureka/
在配置檔案
application.yml
加入相關配置,從
service-id
為
config-server
的 配置服務 讀取相關 配置檔案。
spring:
application:
name: config-client
cloud:
config:
fail-fast: true
discovery:
enabled: true
service-id: config-server
profiles:
active: dev
server:
port: 8762
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
重新啟動應用程式
config-server
和
config-client
,再次通路
http://localhost:8762/foo
,服務端的響應資料如下:
foo version 2
隻需要啟動多個
config-server
執行個體,即可搭建一個 高可用 的
config-server
叢集。
5. 使用Spring Cloud Bus重新整理配置
Spring Cloud Bus
将 分布式節點 通過輕量級的 消息代理 連接配接起來。它可以用于 廣播配置檔案 的更改或者 服務之間 的通訊,也可以用于 監控。在 分布式配置檔案 被更改後,可以通過
Spring Cloud Bus
通知各個微服務中的即時重新整理 本地配置。
5.1. 改造config-client
在
config-client
的
pom.xml
裡面加入 起步依賴
spring-cloud-starter-bus-amqp
。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
在項目的配置檔案
application.yml
檔案中添加
RabbitMQ
的相關配置,包括
RabbitMQ
的 位址、端口、使用者名 和 密碼。為了友善驗證,将
management.security.enabled
改為
false
。
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
management.security.enabled=false
最後,在需要更新屬性的 配置類 上加
@RefreshScope
注解。
@RefreshScope
@RestController
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
@Value("${foo}")
private String foo;
@RequestMapping(value = "/foo")
public String foo(){
return foo;
}
}
依次啟動應用,啟動兩個
config-client
執行個體,端口 分别為
8762
和
8763
。啟動完成後,通路
http://localhost:8762/foo
或者
http://localhost:8763/foo
,服務端響應資料如下:
foo version 2
更改遠端
Git
倉庫 配置檔案 的
config-client-dev.properties
,将
foo
的值改為
“foo version 3”
。
通路
http://localhost:8762/bus/refresh
請求 重新整理配置,設定
“destination”
參數為 待重新整理 屬性的 服務名稱。例如
“http://localhost:8762/bus/refresh?destination=config-client:**”
,即 重新整理服務名 為
config-client
的所有 服務執行個體。
再次通路
http://localhost:8762/foo
和
http://localhost:8763/foo
,服務端響應資料如下:
foo version 3
測試結果表明,
/bus/refresh
通知服務名為
config-client
的所有執行個體 重新整理 了本地的
foo
屬性配置。
參考
- 方志朋《深入了解Spring Cloud與微服務建構》
歡迎關注技術公衆号: 零壹技術棧
本帳号将持續分享後端技術幹貨,包括虛拟機基礎,多線程程式設計,高性能架構,異步、緩存和消息中間件,分布式和微服務,架構學習和進階等學習資料和文章。