【源碼分析】Nacos服務注冊源碼分析-客戶端

Nacos客戶端入口

首先在我們使用Nacos時,會在客戶端引入對應的依賴,例如需要Nacos的注冊中心功能需要引入

        <!--nacos-discovery  注冊中心依賴--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>

而熟悉Springboot的自然知道,為什么引用一個starter就能引入對應的功能?這離不開Springboot的自動配置功能,這也是其特點之一。
而說到自動配置,那自然離不開自動配置類,他即是功能的入口。
那Nacos有哪些自動配置類呢?

NacosServiceAutoConfiguration

這是Nacos服務器通信的基礎設施,是整個 Nacos 集成的"連接管理中心"。

@Configuration(proxyBeanMethods = false
)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosServiceAutoConfiguration {public NacosServiceAutoConfiguration() {}@Beanpublic NacosServiceManager nacosServiceManager() {return new NacosServiceManager();}// Spring 應用 → NacosServiceManager → Nacos SDK → Nacos 服務器}

NacosServiceManager 被多個 Nacos 相關組件使用:

服務發現組件:
NacosServiceDiscovery 使用它獲取 NamingService 實例
NacosRegistration 使用它進行服務注冊

配置中心組件:
NacosConfigManager 使用它獲取 ConfigService 實例
配置刷新機制依賴它提供的服務對象

延遲初始化: NacosServiceManager 不會在創建時立即連接 Nacos 服務器,而是采用延遲初始化策略

按需創建服務對象:
當系統需要 NamingService (服務發現) 時,按需創建并緩存
當系統需要 ConfigService (配置中心) 時,按需創建并緩存

服務對象緩存機制:

基于屬性(如命名空間、分組)創建緩存鍵
相同配置的服務請求復用同一個服務對象實例
避免重復創建連接,優化資源使用

生命周期管理:
與 Spring 容器生命周期綁定
在應用關閉時釋放資源、關閉連接

NacosDiscoveryAutoConfiguration

這是Nacos的服務發現自動配置類,主要有如下功能

  • 自動裝配 Nacos 服務發現組件
  • 初始化服務發現相關的基礎設施 Bean
  • 使應用能夠與 Nacos 服務器進行服務注冊與發現交互
@Configuration(proxyBeanMethods = false
)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryAutoConfiguration {public NacosDiscoveryAutoConfiguration() {}@Bean@ConditionalOnMissingBeanpublic NacosDiscoveryProperties nacosProperties() {return new NacosDiscoveryProperties();}@Bean@ConditionalOnMissingBean // 需要傳入NacosServiceManager ,通過其進行服務發現public NacosServiceDiscovery nacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties, NacosServiceManager nacosServiceManager) { return new NacosServiceDiscovery(discoveryProperties, nacosServiceManager);}
}

NacosServiceRegistryAutoConfiguration

上面兩個,一個是提供操作服務的Service,一個是提供服務發現的功能,那這個就是提供自動注冊的功能,其自動配置類如下:

@Configuration(proxyBeanMethods = false
)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled // 自定義Condition注解,具體參考自動配置相關知識
@ConditionalOnProperty(value = {"spring.cloud.service-registry.auto-registration.enabled"},matchIfMissing = true
)
// 用于控制自動配置順序
@AutoConfigureAfter({AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class, NacosDiscoveryAutoConfiguration.class})
public class NacosServiceRegistryAutoConfiguration {public NacosServiceRegistryAutoConfiguration() {}@Bean // 用于提供注冊功能的Service,其調用NacosServiceManager 進行實現 父類為 ServiceRegistry<R>public NacosServiceRegistry nacosServiceRegistry(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties nacosDiscoveryProperties) {return new NacosServiceRegistry(nacosServiceManager, nacosDiscoveryProperties);}@Bean // 承載服務注冊所需的實例信息,是注冊數據的容器@ConditionalOnBean({AutoServiceRegistrationProperties.class})public NacosRegistration nacosRegistration(ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers, NacosDiscoveryProperties nacosDiscoveryProperties, ApplicationContext context) {return new NacosRegistration((List)registrationCustomizers.getIfAvailable(), nacosDiscoveryProperties, context);}@Bean // 自動服務注冊的觸發器,監聽事件并執行注冊@ConditionalOnBean({AutoServiceRegistrationProperties.class})public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration);}
}

自動注冊剖析

在上述第三個自動配置生效后,會返回一個 new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration);
分析其繼承關系。
在這里插入圖片描述
可以發現其關系圖中,有 ApplicationListener< WebServerInitializedEvent > 這個類,其作用是會監聽對應事件,而這個事件就是WebServerInitializedEvent 代表嵌入式 Web 服務器已完成初始化并啟動的通知機制。

public void onApplicationEvent(WebServerInitializedEvent event) {ApplicationContext context = event.getApplicationContext();if (!(context instanceof ConfigurableWebServerApplicationContext) || !"management".equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) {this.port.compareAndSet(0, event.getWebServer().getPort());this.start(); // start方法}}
==

start 方法

public void start() {if (!this.isEnabled()) {if (logger.isDebugEnabled()) {logger.debug("Discovery Lifecycle disabled. Not starting");}} else {if (!this.running.get()) {this.context.publishEvent(new InstancePreRegisteredEvent(this, this.getRegistration()));this.registrationLifecycles.forEach((registrationLifecycle) -> {registrationLifecycle.postProcessBeforeStartRegister(this.getRegistration());});this.register(); // 進行注冊this.registrationLifecycles.forEach((registrationLifecycle) -> {registrationLifecycle.postProcessAfterStartRegister(this.getRegistration());});if (this.shouldRegisterManagement()) {this.registrationManagementLifecycles.forEach((registrationManagementLifecycle) -> {registrationManagementLifecycle.postProcessBeforeStartRegisterManagement(this.getManagementRegistration());});this.registerManagement();this.registrationManagementLifecycles.forEach((registrationManagementLifecycle) -> {registrationManagementLifecycle.postProcessAfterStartRegisterManagement(this.getManagementRegistration());});}this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));this.running.compareAndSet(false, true);}}}

register方法

private final ServiceRegistry<R> serviceRegistry;
......
protected void register() {if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {log.debug("Registration disabled.");} else {if (this.registration.getPort() < 0) {this.registration.setPort(this.getPort().get());}super.register();}}
// ==> super.register()
protected void register() {this.serviceRegistry.register(this.getRegistration()); // NacosRegistration}

serviceRegistry.register

public void register(Registration registration) {if (StringUtils.isEmpty(registration.getServiceId())) {log.warn("No service to register for nacos client...");} else {NamingService namingService = this.namingService();String serviceId = registration.getServiceId();String group = this.nacosDiscoveryProperties.getGroup();Instance instance = this.getNacosInstanceFromRegistration(registration);try {namingService.registerInstance(serviceId, group, instance); // 進行注冊log.info("nacos registry, {} {} {}:{} register finished", new Object[]{group, serviceId, instance.getIp(), instance.getPort()});} catch (Exception var7) {Exception e = var7;if (this.nacosDiscoveryProperties.isFailFast()) {log.error("nacos registry, {} register failed...{},", new Object[]{serviceId, registration.toString(), e});ReflectionUtils.rethrowRuntimeException(e);} else {log.warn("Failfast is false. {} register failed...{},", new Object[]{serviceId, registration.toString(), e});}}}}

namingService.registerInstance

public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {NamingUtils.checkInstanceIsLegal(instance);this.checkAndStripGroupNamePrefix(instance, groupName);this.clientProxy.registerService(serviceName, groupName, instance); // 通過代理去獲取對應的注冊服務}

clientProxy.registerService

public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {this.getExecuteClientProxy(instance).registerService(serviceName, groupName, instance);}

getExecuteClientProxy

 private NamingClientProxy getExecuteClientProxy(Instance instance) {return (NamingClientProxy)(!instance.isEphemeral() && !this.grpcClientProxy.isAbilitySupportedByServer(AbilityKey.SERVER_SUPPORT_PERSISTENT_INSTANCE_BY_GRPC) ? this.httpClientProxy : this.grpcClientProxy);}

是否臨時服務判斷

Nacos 提供兩種注冊方式,一種是臨時,會進行心跳檢測,如果心跳檢測不超過,或者超時,就會被任務不健康實例,會對其進行下線,其次會將其加入一個隊列中,去檢測是否健康,如果不健康,那就移除。
一種是永久注冊,下面詳細介紹

臨時實例 (Ephemeral = true)

  1. 生命周期特點

    • 基于心跳維持,客戶端需要定期發送心跳包
    • 如果一定時間內未收到心跳,Nacos會自動將實例標記為不健康,并最終移除
  2. 適用場景

    • 適合大多數微服務場景,特別是云原生環境
    • 實例會隨應用的啟停自動注冊和注銷
  3. 數據存儲

    • 存儲在內存中,提供更高的性能
    • 在Nacos服務器重啟時數據會丟失

持久化實例 (Ephemeral = false)

  1. 生命周期特點

    • 實例信息持久化到磁盤
    • 不依賴心跳維持,即使客戶端宕機實例也不會被自動移除
  2. 適用場景

    • 適合那些需要保持穩定注冊狀態的場景
    • 如某些關鍵基礎設施服務,需要手動管理其上下線
  3. 數據存儲

    • 數據持久化到磁盤數據庫中
    • Nacos重啟后數據仍然存在

HttpClient.registerService

public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {LogUtils.NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}", new Object[]{this.namespaceId, serviceName, instance});String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);if (instance.isEphemeral()) {throw new UnsupportedOperationException("Do not support register ephemeral instances by HTTP, please use gRPC replaced.");} else {Map<String, String> params = new HashMap(32);params.put("namespaceId", this.namespaceId);params.put("serviceName", groupedServiceName);params.put("groupName", groupName);params.put("clusterName", instance.getClusterName());params.put("ip", instance.getIp());params.put("port", String.valueOf(instance.getPort()));params.put("weight", String.valueOf(instance.getWeight()));params.put("enable", String.valueOf(instance.isEnabled()));params.put("healthy", String.valueOf(instance.isHealthy()));params.put("ephemeral", String.valueOf(instance.isEphemeral()));params.put("metadata", JacksonUtils.toJson(instance.getMetadata()));this.reqApi(UtilAndComs.nacosUrlInstance, params, "POST");}}

Grpc.registerService

 public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {LogUtils.NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance {}", new Object[]{this.namespaceId, serviceName, instance});if (instance.isEphemeral()) {this.registerServiceForEphemeral(serviceName, groupName, instance);} else {this.doRegisterServiceForPersistent(serviceName, groupName, instance);}}

自上,自動注冊服務就到此為止

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/898031.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898031.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898031.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java中關于Optional的 orElse 操作,以及 orElse 與 orElseGet 的區別

文章目錄 1. 大概說明2. 詳細分析2.1 .orElse 操作2.2 .orElse 的作用&#xff1a;避免空指針異常2.3 為什么要用&#xff1f;2.4 orElseGet如何使用2.5 orElse和orElseGet的區別 1. 大概說明 這篇文章的目的是為了說明&#xff1a; orElse 如何使用orElseGet 如何使用兩者的…

數據結構-樹(詳解)

目錄 一、樹的基本概念二、樹的節點結構三、樹的基本操作&#xff08;一&#xff09;插入操作&#xff08;二&#xff09;刪除操作&#xff08;三&#xff09;查找操作&#xff08;四&#xff09;遍歷操作 四、樹的實現五、總結 一、樹的基本概念 樹是一種非線性數據結構&…

【eNSP實戰】配置端口映射(NAT Server)

拓圖 要求&#xff1a; 將AR1上的GE 0/0/1接口的地址從TCP協議的80端口映射到內網 Web服務器80端口 AR1接口配置 interface GigabitEthernet0/0/0ip address 192.168.0.1 255.255.255.0 # interface GigabitEthernet0/0/1ip address 11.0.1.1 255.255.255.0 # ip route-s…

RabbitMQ 基本原理詳解

1. 引言 在現代分布式系統中&#xff0c;消息隊列&#xff08;Message Queue&#xff09;是實現異步通信、解耦系統組件、提高系統可靠性和擴展性的重要工具。RabbitMQ 作為一款開源的消息中間件&#xff0c;因其高性能、易用性和豐富的功能&#xff0c;被廣泛應用于各種場景。…

算法——層序遍歷和中序遍歷構造二叉樹

晴問 #include <iostream> #include <vector> #include <queue> #include <unordered_map>using namespace std;struct TreeNode {int data;TreeNode *left;TreeNode *right;TreeNode(int data) : data(data), left(nullptr), right(nullptr) {} };//…

prometheus自定義監控(pushgateway和blackbox)和遠端存儲VictoriaMetrics

1 pushgateway采集 1.1 自定義采集鍵值 如果自定義采集需求時&#xff0c;就可以通過寫腳本 定時任務定期發送數據到 pushgateway 達到自定義監控 1.部署 pushgateway&#xff0c;以 10.0.0.42 節點為例 1.下載組件 wget https://github.com/prometheus/pushgateway/relea…

feign配置重試次數不生效

一、問題產生 自定義重試次數&#xff0c;實現如下 ConditionalOnProperty(prefix "feign.client", name "enable", havingValue "true") Configuration public class FeignConfig {Beanpublic FeignInterceptor feignInterceptor() {retur…

Dify使用部署與應用實踐

最近在研究AI Agent&#xff0c;發現大家都在用Dify&#xff0c;但Dify部署起來總是面臨各種問題&#xff0c;而且我在部署和應用測試過程中也都遇到了&#xff0c;因此記錄如下&#xff0c;供大家參考。Dify總體來說比較靈活&#xff0c;擴展性比較強&#xff0c;適合基于它做…

二叉樹的統一迭代法 標記法

我們以中序遍歷為例&#xff0c;在二叉樹&#xff1a;聽說遞歸能做的&#xff0c;棧也能做&#xff01; (opens new window)中提到說使用棧的話&#xff0c;無法同時解決訪問節點&#xff08;遍歷節點&#xff09;和處理節點&#xff08;將元素放進結果集&#xff09;不一致的情…

BaseActivity 和 BaseFragment 的現代化架構:ViewBinding 與 ViewModel 的深度整合

BaseActivity 和 BaseFragment 實現&#xff0c;集成了 View Binding&#xff0c;并增加了對 Lifecycle 和 ViewModel 的支持&#xff0c;同時進一步簡化了代碼結構&#xff0c;使其更易用、更靈活。 啟用 View Binding 確保在 build.gradle 中啟用了 View Binding&#xff1a…

從零開始學習機器人---如何高效學習機械原理

如何高效學習機械原理 1. 理解課程的核心概念2. 結合圖形和模型學習3. 掌握公式和計算方法4. 理論與實踐相結合5. 總結和復習6. 保持好奇心和探索精神 總結 機械原理是一門理論性和實踐性都很強的課程&#xff0c;涉及到機械系統的運動、動力傳遞、機構設計等內容。快速學習機械…

剖析sentinel的限流和熔斷

sentinel的限流和熔斷 前言源碼分析滑動窗口源碼限流源碼熔斷源碼 完結撒花&#xff0c;sentinel源碼還是挺簡單的&#xff0c;如有需要收藏的看官&#xff0c;順便也用發財的小手點點贊哈&#xff0c;如有錯漏&#xff0c;也歡迎各位在評論區評論&#xff01; 前言 平時發起一…

硬盤分區誤刪后的數據救贖

一、硬盤分區誤刪的概述 硬盤分區誤刪&#xff0c;是許多電腦用戶在使用過程中可能遭遇的棘手問題。分區&#xff0c;作為硬盤上存儲數據的邏輯單元&#xff0c;一旦被誤刪除&#xff0c;不僅會導致該分區內的所有數據瞬間消失&#xff0c;還可能影響到整個硬盤的存儲結構和數…

代碼隨想錄算法訓練營第三十五天(20250303) |01背包問題 二維,01背包問題 一維,416. 分割等和子集 -[補卡20250316]

01背包問題 二維 鏈接 遍歷物品沒有大小順序要求重點是模擬&#xff0c;推導出遞推公式 #include <iostream> #include <vector>int main(){int m, n;std::cin>>m>>n;std::vector<int> weight(m,0),value(m,0);for(int i{0}; i<m; i){std:…

老牌軟件,方便處理圖片,量大管飽。

今天介紹的圖片查看器名字是&#xff1a;FastStone Image Viewer&#xff0c;是一款可查看、編輯、批量重命名、批量轉換的圖片查看軟件。文末有分享鏈接。 軟件以資源管理器的方式管理你電腦里的圖片&#xff0c;點擊左側可選擇文件夾&#xff0c;右邊可預覽圖片。 軟妹用得最…

【數據庫相關】mysql數據庫巡檢

mysql數據庫巡檢 巡檢步驟**一、基礎狀態檢查****二、服務器資源監控****CPU使用****內存使用****磁盤I/O****網絡流量** **三、數據庫內部健康度****全局狀態****慢查詢監控****鎖與并發** **四、存儲引擎健康****InnoDB引擎****MyISAM引擎** **五、日志與備份****六、安全與權…

Python進階編程總結

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家&#xff0c;歷代文學網&#xff08;PC端可以訪問&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移動端可微信小程序搜索“歷代文學”&#xff09;總架構師&#xff0c;15年工作經驗&#xff0c;…

Redis復制(replica)主從模式

Redis主從復制 Redis 的復制&#xff08;replication&#xff09;功能允許用戶根據一個 Redis 服務器來創建任意多個該服務器的復制品&#xff0c;其中被復制的服務器為主服務器&#xff08;master&#xff09;&#xff0c;而通過復制創建出來的服務器復制品則為從服務器&#…

Adobe Premiere Pro2023配置要求

Windows 系統 最低配置 處理器&#xff1a;Intel 第六代或更新版本的 CPU&#xff0c;或 AMD Ryzen? 1000 系列或更新版本的 CPU&#xff0c;需要支持 Advanced Vector Extensions 2&#xff08;AVX2&#xff09;。操作系統&#xff1a;Windows 10&#xff08;64 位&#xff…

【Kubernets】Deployment 和 StatefulSet 有什么區別?什么時候用 StatefulSet?

Deployment 和 StatefulSet 的區別 在 Kubernetes 中&#xff0c;Deployment 和 StatefulSet 都用于管理 Pod&#xff0c;但它們適用于不同的場景。 1. Deployment&#xff1a;管理無狀態應用 特點&#xff1a; 無狀態&#xff1a;Pod 之間相互獨立&#xff0c;不需要保持順…