Spring Cloud開發實踐(七): 整合Consul設定中心

2023-06-01 21:01:39

目錄

Spring Cloud Consul Config

Consul 通過 Key/Value 功能集中管理儲存設定資訊, 通過 Spring Cloud Consul Config 可以實現 Config Server 和 Client 的關聯. 在 Spring 啟動的 bootstrap 階段, 設定會被載入環境上下文.

設定字首, 路徑和優先順序

預設情況下, 設定的路徑字首是 /config , 不同的 application 和 profile 對應不同的設定路徑, 例如對應應用 "testApp" 和 "dev" profile 的設定, 會涉及以下路徑

config/testApp,dev/
config/testApp/
config/application,dev/
config/application/

這個列表從上往下分別對應的設定優先順序從高到低, 優先順序高的同樣設定項會覆蓋優先順序低的設定項.

  • config/application/ 全域性公共設定, 對應使用 config 字首的所有應用
  • config/application,dev/ 全域性dev公共設定, 對應使用 config 字首的所有, 且啟用 dev profile 的應用
  • config/testApp/ 對應使用 config 字首的, 名稱為 testApp 的應用
  • config/testApp,dev/ 對應使用 config 字首的, 名稱為 testApp, 且啟用 dev profile 的應用

注意: 設定對應的 profile 和節點應用名是平級的, config/service-name,dev/data 這樣, data 是設定的子項, 不要把 profile 加到 data 去了

在專案中啟用 Consul Config

如果要使用 Consul 的分散式設定(Distributed Configuration), 需要新增 spring-cloud-starter-consul-config 的依賴

spring-cloud-starter-consul-discovery 不帶 spring-cloud-starter-consul-config, 如果需要用 Consul Config, 需要單獨新增依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>

也可以直接用 spring-cloud-starter-consul-all, 包含了 spring-cloud-starter-consul-discovery 和 spring-cloud-starter-consul-config

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-all</artifactId>
</dependency>

組態檔 application.yml

新增了 consul-config 依賴之後, 在 application.yml 就要增加對應的設定 spring.config.import = consul: 否則啟動會報錯,
Spring Boot 在 2.4 版本之後新增了這個項(spring.config.import property)用於匯入設定, 並且是預設的設定方式.

# properties
spring.config.import=optional:consul:
# yaml
spring:
  config:
    import: 'consul:'

上面的設定, 如果啟動時import失敗會導致啟動失敗, 如果不強制 import, 可以加上 optional:

# properties
spring.config.import=optional:consul:
# yaml
spring:
  config:
  import: 'optional:consul:'

上面的這兩個設定, 都會用預設的地址 http://localhost:8500 去請求 Consul 服務, 如果需要自定義地址, 可以通過設定spring.cloud.consul.hostspring.cloud.consul.port,

spring:
  cloud:
    consul:
      host: 10.123.123.123
      port: 8501

或者使用

spring.config.import=optional:consul:myhost:8500

對應以上設定, 在 Spring 啟動的 bootstrap 階段會通過 Consul 去獲取 key = config/dummy-service/data 對應的 value (假定這個模組的 application.name = dummy-service),
對應value格式為 yaml, 需要增加設定

# yaml
spring:
  cloud:
    consul:
      config:
        format: YAML
        prefix: config
        data-key: data

其中

  • format: YAML 設定設定格式
  • prefix: config修改 config/dummy-service/data 的字首
  • data-key: data修改 config/dummy-service/data 的字尾

預設的請求路徑生成基於

  1. spring.cloud.consul.config.name , 值預設等於 spring.application.name
  2. spring.cloud.consul.config.default-context , 這個值預設等於 application
  3. spring.profiles.active , 可以在啟動時通過 VM Option -Dspring.profiles.active=xxx 指定

如果不想用預設的, 想自己指定, 可以用如下的方式

# properties
spring.config.import=optional:consul:myhost:8500/config/custom/context/one;/config/custom/context/two

上面的設定將只從這兩個Key/Value路徑讀取設定, 注意路徑的對應關係, 在import中體現字首 config, 但是不體現字尾 data

  • /config/custom/context/one/data
  • /config/custom/context/two/data

設定自動更新, Config Watch

Consul Config Watch 使用 consul 的路徑字首對設定更新進行檢查, 當設定變化時會產生一個 Refresh Event, 等價於請求 /refresh actuator endpoint.

預設的檢查頻率為 1000 單位毫秒, 可以通過 spring.cloud.consul.config.watch.delay 設定

如果要禁用設定自動更新, 需要設定 spring.cloud.consul.config.watch.enabled=false

Consul 設定管理

通過 WEB 介面

預設為 http://127.0.0.1:8500 可以在 Key/Value 中直接新增, 記得格式要改為 YAML

通過命令列

讀取

$ ./consul kv get foo
bar

$ ./consul kv get config/application/data
cassandra:
  host: 127.0.0.1:9042,127.0.0.2:9042
  user: my_user
  password: my_pass

使用檔案data.yml中的內容, 直接寫入

$  ./consul kv put config/application/data @data.yml
Success! Data written to: config/application/data
The data can be retrieved the same way,

使用設定

經過以上設定, 在專案中就可以通過 @Configuration 獲取 Consul 中設定的資訊

@Slf4j
@Configuration
public class CommonConfig {
    @Value("${common.name}")
    private String name = "Dummy";
    @Value("${common.code}")
    private String code = "001";

    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public String getCode() {return code;}
    public void setCode(String code) {this.code = code;}

    @PostConstruct
    public void postConstruct() {
        log.info("name: {}", name);
        log.info("code: {}", code);
    }
}

參考