Consul 通過 Key/Value 功能集中管理存儲配置信息, 通過 Spring Cloud Consul Config 可以實現 Config Server 和 Client 的關聯. 在 Spring 啟動的 bootstrap 階段, 配置會被載入環境上下文. ...
目錄
- Spring Cloud開發實踐(一): 簡介和根模塊
- Spring Cloud開發實踐(二): Eureka服務和介面定義
- Spring Cloud開發實踐(三): 介面實現和下游調用
- Spring Cloud開發實踐(四): Docker部署
- Spring Cloud開發實踐(五): Consul - 服務註冊的另一個選擇
- Spring Cloud開發實踐(六): 基於Consul和Spring Cloud 2021.0的演示項目
- Spring Cloud開發實踐(七): 集成Consul配置中心
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.host
和spring.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 的尾碼
預設的請求路徑生成基於
- spring.cloud.consul.config.name , 值預設等於 spring.application.name
- spring.cloud.consul.config.default-context , 這個值預設等於 application
- 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);
}
}