Nacos解讀:配置中心與Spring Cloud的整合
之前這篇文章介紹了Nacos Config Client的實現,今天繼續聊下Nacos Config Client與Spring Cloud的結合。
官方示例
引入依賴
在 dependencyManagement
中新增如下配置。
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>0.2.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
引入 Nacos Config Starter。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
配置Nacos Config元資料
在 bootstrap.properties
配置檔案中配置Nacos Config元資料。
spring.application.name=nacos-config-example spring.cloud.nacos.config.server-addr=127.0.0.1:8848
使用配置
應用會從Nacos Config中獲取dataId為 nacos-config-example.properties
,group為 DEFAULT_GROUP
的配置,並新增在 Spring Environment 的 PropertySources 中。可以使用 @Value 註解來將對應的配置注入到相應欄位,並新增 @RefreshScope 開啟動態重新整理功能。
@RefreshScope class SampleController { @Value("${user.name}") String userName; @Value("${user.age}") int age; }
可選配置
現把目前支援的配置項總結如下,配置字首為 spring.cloud.nacos.config.
。
key | 預設值 | 說明 |
---|---|---|
server-addr | 服務端地址 | |
prefix | {spring.application.name} | DataId字首 |
group | DEFAULT_GROUP | Group |
file-extension | properties | dataID字尾及內容檔案格式 |
encode | UTF-8 | 配置的編碼 |
timeout | 3000 | 獲取配置的超時時間,單位為 ms |
namespace | 配置的名稱空間 | |
access-key | 阿里雲AccessKey | |
secret-key | 阿里雲SecretKey | |
context-path | 服務端 API 的相對路徑 | |
endpoint | 服務端接入點 | |
cluster-name | 叢集名 | |
name | 如果未配置prefix,會把該值當prefix | |
sharedDataids | 共享配置的dataId,逗號分隔 | |
refreshableDataids | 共享配置中允許自動重新整理的dataId | |
extConfig | 額外配置項 | |
refresh.enabled | true | 是否開啟監聽和自動重新整理 |
spring.factories
在聊 Nacos Naming與Spring Cloud的結合 時,曾簡單介紹了自動裝配的背景知識。Nacos Config的spring.factories配置如下。
org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.alibaba.nacos.NacosConfigBootstrapConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.alibaba.nacos.NacosConfigAutoConfiguration,\ org.springframework.cloud.alibaba.nacos.endpoint.NacosConfigEndpointAutoConfiguration org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.cloud.alibaba.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer
其中有一些之前沒有提過的型別,在此簡單介紹一下,想要詳細瞭解可以參考我給出的連結。
FailureAnalyzer
FailureAnalyzer是用於啟動失敗時,向控制檯輸出一些有用的資訊以幫助排查問題的。簡單來看下Nacos的實現。
public class NacosConnectionFailureAnalyzer extends AbstractFailureAnalyzer<NacosConnectionFailureException> { @Override protected FailureAnalysis analyze(Throwable rootFailure, NacosConnectionFailureException cause) { return new FailureAnalysis("Application failed to connect to Nacos server", "check your nacos server config", cause); } }
當連線Nacos服務端失敗丟擲 NacosConnectionFailureException
時,會向控制檯輸出如程式碼中的資訊。但是,目前版本中並沒有任何地方會丟擲 NacosConnectionFailureException
,因此目前FailureAnalysis實際是無效的,可能會在後續版本中增加吧。
BootstrapConfiguration
Spring Cloud引入了 Bootstrap Application Context
, Bootstrap Application Context
作為應用的 Main Application Context
的父Context,優先於 Main Application Context
初始化。不同於 Main Application Context
載入 application.properties
(或 application.yml
), Bootstrap Application Context
會使用 bootstrap.properties
(或 bootstrap.yml
),所以在上面的示例中可以看到Nacos Config的相關配置放在了 bootstrap.properties
中。
spring.factories
中 BootstrapConfiguration
類似於 EnableAutoConfiguration
等配置,但 BootstrapConfiguration
配置的類註冊的Bean會在 Main Application Context
初始化之前建立。
Beans
接下來我們看一下Nacos Config註冊了哪些Bean。如 spring.factories
所示,Nacos Config有 NacosConfigBootstrapConfiguration
、 NacosConfigAutoConfiguration
、 NacosConfigEndpointAutoConfiguration
、 NacosConnectionFailureAnalyzer
四個配置類,最後一個 NacosConnectionFailureAnalyzer
上面已經簡單分析過並且目前實質也沒有用到,這裡就不再重複。重點分析其他三個配置類。
NacosConfigBootstrapConfiguration
NacosConfigBootstrapConfiguration註冊了2個Bean, NacosConfigProperties
和 NacosPropertySourceLocator
。
@Bean @ConditionalOnMissingBean public NacosConfigProperties nacosConfigProperties() { return new NacosConfigProperties(); } @Bean public NacosPropertySourceLocator nacosPropertySourceLocator( NacosConfigProperties nacosConfigProperties) { return new NacosPropertySourceLocator(nacosConfigProperties); }
NacosConfigProperties
即對應上文提到的那些可選配置。
NacosPropertySourceLocator
實現了 PropertySourceLocator
介面, PropertySourceLocator
介面只有一個 locate(Environment environment)
方法,返回值為 PropertySource
,Spring會把返回的 PropertySource
新增到Spring的Environment中,所有我們才可以在程式中通過 @Value
使用這些配置。可參考: Customizing the Bootstrap Property Sources
Nacos Config的實現如下。
@Override public PropertySource<?> locate(Environment env) { // 省略... CompositePropertySource composite = new CompositePropertySource( NACOS_PROPERTY_SOURCE_NAME); loadSharedConfiguration(composite); loadExtConfiguration(composite); loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env); return composite; }
Nacos Config返回的是一個 CompositePropertySource
, CompositePropertySource
支援新增多個PropertySource,獲取配置時會依照新增的順序依次獲取。
Nacos Config的配置可以分為3種: SharedConfiguration
、 ExtConfiguration
、 ApplicationConfiguration
。
程式碼的實現雖然是按照 SharedConfiguration
-> ExtConfiguration
-> ApplicationConfiguration
的順序依次載入的,但向 CompositePropertySource
新增時呼叫的是 addFirstPropertySource()
方法,會把配置新增到首位。
因此,配置使用的實際順序是 ApplicationConfiguration
-> ExtConfiguration
-> SharedConfiguration
。
而這幾種配置的獲取實際就是利用了Nacos Config Client提供的API,呼叫 String getConfig(String dataId, String group, long timeoutMs)
方法從Nacos服務端獲取,
關於這幾個不同配置型別的使用大家還可以參考didi大佬的教程—— Spring Cloud Alibaba基礎教程:Nacos配置的多檔案載入與共享配置 。
NacosConfigAutoConfiguration
NacosConfigAutoConfiguration中註冊的幾個Bean主要是用於動態重新整理配置。關鍵的Bean是 NacosContextRefresher
。之前介紹Nacos Config Client時介紹過支援設定Listener來監聽配置的變化,這裡的動態重新整理也是利用這個來實現的。
註冊監聽
NacosContextRefresher會監聽 ApplicationReadyEvent
事件,註冊Nacos各個配置項的監聽是在接收到 ApplicationReadyEvent
事件時進行的。
@Override public void onApplicationEvent(ApplicationReadyEvent event) { // many Spring context if (this.ready.compareAndSet(false, true)) { this.registerNacosListenersForApplications(); } } private void registerNacosListenersForApplications() { if (refreshProperties.isEnabled()) { for (NacosPropertySource nacosPropertySource : NacosPropertySourceRepository .getAll()) { if (!nacosPropertySource.isRefreshable()) { continue; } String dataId = nacosPropertySource.getDataId(); registerNacosListener(nacosPropertySource.getGroup(), dataId); } } }
從程式碼可以看到只會對開啟了動態重新整理的dataId註冊監聽。對於不同的配置型別策略不同。
spring.cloud.nacos.config.ext-config[0].refresh=true spring.cloud.nacos.config.refreshableDataids
如果需要關閉所有的動態重新整理,可以將 spring.cloud.nacos.config.refresh.enabled
設定為false。
Listener
註冊的Listener程式碼如下。
@Override public void receiveConfigInfo(String configInfo) { refreshCountIncrement(); String md5 = ""; if (!StringUtils.isEmpty(configInfo)) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md5 = new BigInteger(1, md.digest(configInfo.getBytes("UTF-8"))) .toString(16); } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { log.warn("[Nacos] unable to get md5 for dataId: " + dataId, e); } } refreshHistory.add(dataId, md5); applicationContext.publishEvent( new RefreshEvent(this, null, "Refresh Nacos config")); if (log.isDebugEnabled()) { log.debug("Refresh Nacos config group " + group + ",dataId" + dataId); } }
重新整理配置的關鍵程式碼是 applicationContext.publishEvent(new RefreshEvent(this, null, "Refresh Nacos config"));
,分發了一個 RefreshEvent
事件。
之後就交由Spring Cloud處理了, RefreshEvent
事件與呼叫 /refresh
的Endpoint是一樣的,會重建Environment,從而會再次呼叫 PropertySourceLocator
介面的 locate
方法,Nacos就會把更新後的 PropertySource
返回。其他資訊可以參考 Refresh Scope 相關文件或其他文章。
NacosConfigEndpointAutoConfiguration
NacosConfigEndpointAutoConfiguration用於暴露Endpoint,path為 /nacos_config
【Spring Boot 1.x】或 /actuator/nacos-config
【Spring Boot 2.x】返回的資訊包括3個部分:
- NacosConfigProperties:Nacos Config Starter 本身的配置。
- Sources:表示此客戶端從哪些 Nacos Config 配置項中獲取了資訊。
- RefreshHistory:表示動態重新整理的歷史記錄,最多儲存20條,
見官網文件的示例:
actuator
總結
Nacos Config藉助Spring提供的特性實現了配置中心所需的兩大功能:
PropertySourceLocator RefreshEvent