程式設計師你是如何使用Nacos作為配置中心的?
阿新 • • 發佈:2020-10-10
![file](https://img2020.cnblogs.com/other/268922/202010/268922-20201009234957286-366094551.jpg)
> 假如你使用的是spring-cloud-alibaba微服務技術棧
# 單個服務獨有配置檔案
即去除應用程式的狀態,配置統一外部化管理,方便進行水平的伸縮。
整合步驟:
假如我有一個應用app-design;
1,引入依賴:
```xml
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
2.2.1.RELEASE
```
2, 配置檔案;
```
spring.cloud.nacos.config.enabled=true
spring.cloud.nacos.config.refresh-enabled=true
spring.cloud.nacos.config.server-addr=${spring.cloud.nacos.discovery.server-addr}
spring.cloud.nacos.config.namespace=${spring.cloud.nacos.discovery.namespace}
```
說明如下:
| 屬性 | 說明 |
| --- | --- |
| spring.cloud.nacos.config.server-addr=${spring.cloud.nacos.discovery.server-addr} | nacos配置中心地址 |
| spring.cloud.nacos.config.namespace=${spring.cloud.nacos.discovery.namespace} | nacos的名稱空間,這裡跟服務發現的配置一致; |
3,使用配置的方式,同本地配置檔案一樣。
@Value @PropertyConfiguration 這些註解都是支援的;
4,確認方式,比如把之前的application.properties的配置放到了配置中心;
![image.png](https://img2020.cnblogs.com/other/268922/202010/268922-20201009234957697-1783037964.png)
本地啟動的時候,讀取到了8081埠和資料庫連線池的配置;
![image.png](https://img2020.cnblogs.com/other/268922/202010/268922-20201009235006569-1599946998.png)
配置中心的連線原理,後面單獨整理出來,知其然並知其所以然。
# 服務之間共享配置檔案
場景:多個後端微服務,在同一個叢集中共用中介軟體的配置資訊。
比如 快取redis, 訊息佇列kafka, 檔案伺服器, 郵件伺服器;
那麼對應的配置檔案沒有必要在所有的後端微服務中單獨存在,這些配置檔案應該放在公共配置檔案中,但是也可以被具體的後端微服務自己的獨有配置檔案覆蓋,使用自己的私有配置;
可結合下圖理解:
![](https://img2020.cnblogs.com/other/268922/202010/268922-20201009235007691-1654129973.svg+xml)
| 問題 | 回答 |
| --- | --- |
| where are we?現狀 | 中介軟體配置分散在很多服務中,配置繁瑣,不方便統一管理 |
| where are we go?目的 | 同一個叢集的中介軟體只維護一份,各服務共享,也可按照需要覆蓋共享的配置; |
| how can we go there?實現路徑 | 基於nacos已有功能實現 |
下面是實際的coding過程和測試用例;
服務app-file;
在服務對應的nacos的namespace中
## 1 引入共享配置
```
#共享中介軟體的配置
spring.cloud.nacos.config.shared-configs[0].data-id=mid.properties
spring.cloud.nacos.config.shared-configs[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.shared-configs[0].refresh=true
```
位置: 模組start下的src/main/resources/bootstrap.properties檔案中
自描述的配置資訊,即引入的共享配置檔案列表有哪些,可以按照需要,配置各種中介軟體的配置資訊;
| key | 說明 |
| --- | --- |
| data-id | _the data id of extended configuration 配置檔名稱,帶上字尾;翻譯:擴充套件配置檔案的資料id |
| group | _the group of extended configuration, the default value is DEFAULT_GROUP 叢集名稱, 從名字來看,支援多叢集的配置檔案 翻譯:擴充套件配置檔案的叢集,預設值是 _DEFAULT_GROUP_ |
| refresh | _whether to support dynamic refresh, the default does not support 是否重新整理 翻譯:是否支援動態重新整理,預設不支援 |
花括號[0] ,裡面的0是序號,如果有多個,按照數字自增順序進行配置;
## 2 在nacos中新增配置檔案
根據實際場景在nacos的test名稱空間中新增配置檔案mid.properties
![image.png](https://img2020.cnblogs.com/other/268922/202010/268922-20201009235008032-1384534892.png)
## 3 獲取配置用例測試
測試介面程式碼:
```java
@ApiOperation("測試獲取公共配置檔案")
@GetMapping("/config/test")
public Response config(){
String redisConfigServers = environment.getProperty("redis.config.servers","null");
return SingleResponse.of(redisConfigServers);
}
```
測試用例:
| 場景 | 期望結果 | 實際結果 | 是否符合預期 |
| --- | --- | --- | --- |
| 獲取共享配置檔案中的配置 | r-wz9sp7dhxjnz16bs1jzhutj.redis.rds.aliyuncs.com:6379 | r-wz9sp7dhxjnz16bs1jzhutj.redis.rds.aliyuncs.com:6379 | 是 |
| 在服務獨有app-file.properties配置中重寫配置redis.config.servers=r-wz9sp7dhxjnz16bs1jzhutj.redis.rds.aliyuncs.com:637905 | r-wz9sp7dhxjnz16bs1jzhutj.redis.rds.aliyuncs.com:637905 | r-wz9sp7dhxjnz16bs1jzhutj.redis.rds.aliyuncs.com:637905 | 是 |
截圖如下:
![image.png](https://img2020.cnblogs.com/other/268922/202010/268922-20201009235008398-1947104286.png)
![image.png](https://img2020.cnblogs.com/other/268922/202010/268922-20201009235008674-698714325.png)
![image.png](https://img2020.cnblogs.com/other/268922/202010/268922-20201009235008921-604219324.png)
# 原始碼分析
掌握用法之後,深入分析原始碼,知其然而知其所以然;
## starter呼叫封裝
使用的starter封裝;
[https://github.com/alibaba/spring-cloud-alibaba/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config](https://github.com/alibaba/spring-cloud-alibaba/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config)
版本: 2.2.1.RELEASE
啟動的時候自動裝配的配置如下:
```java
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.NacosConfigAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer
```
分解一下key,看一下用途:
| key | 說明 |
| --- | --- |
| org.springframework.cloud.bootstrap.BootstrapConfiguration | _A marker interface used as a key in . Entries in* the factories file are used to create the bootstrap application context._
_翻譯:一個標記註解用來作為key 放在META-INF/spring.factories檔案中,檔案中的條目用來建立啟動應用的上下文;_
來源:spring-cloud-context-version.jar
value:
com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration |
| org.springframework.boot.autoconfigure.EnableAutoConfiguration | 註釋太長了,不放這裡.放到附錄中。
來源:spring-boot-autoconfigure-version.jar
com.alibaba.cloud.nacos.NacosConfigAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration |
| org.springframework.boot.diagnostics.FailureAnalyzer | _A {@code FailureAnalyzer} is used to analyze a failure and provide diagnostic* information that can be displayed to the user._
_
翻譯: FailureAnalyzer用來分析錯誤並提供診斷資訊展示給到使用者
來源: spring-boot-version.jar
com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer |
然後看看都自動裝配了什麼?以及自動裝配的過程。
springboot的方式呼叫;
### 1 NacosConfigBootstrapConfiguration
原始碼:
```java
package com.alibaba.cloud.nacos;
import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author xiaojing
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.cloud.nacos.config.enabled", matchIfMissing = true)
public class NacosConfigBootstrapConfiguration {
@Bean
@ConditionalOnMissingBean
public NacosConfigProperties nacosConfigProperties() {
return new NacosConfigProperties();
}
@Bean
@ConditionalOnMissingBean
public NacosConfigManager nacosConfigManager(
NacosConfigProperties nacosConfigProperties) {
return new NacosConfigManager(nacosConfigProperties);
}
@Bean
public NacosPropertySourceLocator nacosPropertySourceLocator(
NacosConfigManager nacosConfigManager) {
return new NacosPropertySourceLocator(nacosConfigManager);
}
}
```
自動裝配流程:
![](https://img2020.cnblogs.com/other/268922/202010/268922-20201009235009216-1421201079.svg+xml)
配置檔案組裝原始碼:
```java
@Override
public PropertySource> locate(Environment env) {
nacosConfigProperties.setEnvironment(env);
ConfigService configService = nacosConfigManager.getConfigService();
if (null == configService) {
log.warn("no instance of config service found, can't load config from nacos");
return null;
}
long timeout = nacosConfigProperties.getTimeout();
nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService,
timeout);
String name = nacosConfigProperties.getName();
String dataIdPrefix = nacosConfigProperties.getPrefix();
if (StringUtils.isEmpty(dataIdPrefix)) {
dataIdPrefix = name;
}
if (StringUtils.isEmpty(dataIdPrefix)) {
dataIdPrefix = env.getProperty("spring.application.name");
}
CompositePropertySource composite = new CompositePropertySource(
NACOS_PROPERTY_SOURCE_NAME);
loadSharedConfiguration(composite);
loadExtConfiguration(composite);
loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
return composite;
}
```
![](https://img2020.cnblogs.com/other/268922/202010/268922-20201009235009387-2622454.svg+xml)
載入應用配置檔案的順序原始碼:
```java
private void loadApplicationConfiguration(
CompositePropertySource compositePropertySource, String dataIdPrefix,
NacosConfigProperties properties, Environment environment) {
String fileExtension = properties.getFileExtension();
String nacosGroup = properties.getGroup();
// load directly once by default
loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup,
fileExtension, true);
// load with suffix, which have a higher priority than the default
loadNacosDataIfPresent(compositePropertySource,
dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true);
// Loaded with profile, which have a higher priority than the suffix
for (String profile : environment.getActiveProfiles()) {
String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
fileExtension, true);
}
}
```
順序如下:
| 序號 | 說明 |
| --- | --- |
| 1 | 載入dataIdPrefix對應的配置檔案 |
| 2 | 載入dataIdPrefix.fileExtension對應的配置檔案 |
| 3 | 載入 dataIdPrefix-activeProfiles.fileExtension對應的配置檔案 |
### 2.1 NacosConfigAutoConfiguration
| 序號 | 說明 |
| --- | --- |
| 1 | NacosConfigProperties nacos配置 |
| 2 | NacosRefreshProperties 已經不建議被使用 |
| 3 | NacosRefreshHistory 刷新歷史 |
| 4 | NacosConfigManager 配置 |
| 5 | NacosContextRefresher 註冊nacos的監聽器到應用 |
### 2.2 NacosConfigEndpointAutoConfiguration
NacosConfigEndpoint
本地配置同步邏輯
```java
@ReadOperation
public Map invoke() {
Map result = new HashMap<>(16);
result.put("NacosConfigProperties", properties);
List all = NacosPropertySourceRepository.getAll();
List
META-INF/spring.factories