Nacos客户端实例注册源码分析-篇一

news2024/11/24 2:07:17

Nacos客户端实例注册源码分析-篇一

版本 nacos 服务器端 nacos 2.0.3

实例客户端注册入口

注册案例

回到之前搭建的服务提供者项目 9002 ,在真实的生产环境下,如果需要让某一个服务注册到 Nacos 的服务当中,我们引入对应的 nacos 发现依赖,配置对应的 yaml 文件即可。

启动服务器端的 nacos 服务(当然线上环境 nacos 服务是一直在线的)

image-20230412203342164

在后端项目当中导入对应的服务依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置相应的 yaml 文件

server:
  port: 9002
spring:
  application:
    name: nacos-provider //服务名
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.188.101:8848 //nacos的服务地址

在启动类添加启动发现客户端注解 @EnableDiscoveryClient

@SpringBootApplication
@EnableDiscoveryClient
public class CloudanlibabaNacos9002Application {

    public static void main(String[] args) {
        SpringApplication.run(CloudanlibabaNacos9002Application.class, args);
    }

}

Nacos 客户端就可以看到相应的服务

image-20230412203856983

image-20230412204101328

那么这个注册的过程是怎么实现的呢?Nacos 到底是怎么从我们配置的 yaml 文件中扫描到相应的注册信息的呢?那我们接着往下看。。。

源码探究

还记得 SpringBoot 项目在通过 Maven 导入依赖后,是怎么实现自动装配的吗?对了,核心就是 spring.factories 文件,那我们就从注册发现的包导入入手。

在普通的 SpringBoot 项目的 pom.xml 当中引入相应的依赖,导入 discovery 的 jar 包

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

image-20230412204722345

image-20230412205507802

  • NacosDiscoveryAutoConfiguration Nacos 发现自动配置
  • RibbonNacosAutoConfiguration Ribbon Nacos 自动配置
  • NacosDiscoveryEndpointAutoConfiguration Nacos 发现端点自动配置
  • NacosServiceRegistryAutoConfiguration Nacos 服务注册自动配置
  • NacosConfigServerAutoConfiguration Nacos 配置的自动配置

可以看到的是 SpringBoot 通过 EnableAutoConfiguration 实现类的扫描自动加载,那么如何知道我们的服务在注册的时候使用的是那个类呢?

其实我们只要找到有 Auto(自动) 修饰的类即可,可以看到的是在 factories 文件当中有 Auto 修饰的类有多个。

因为我们需要了解的客户端的服务注册 ,那么我们只需要找服务注册 **NacosServiceRegistryAutoConfiguration **即可

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.alibaba.cloud.nacos.registry;

import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
import java.util.List;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(
    proxyBeanMethods = false
)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(
    value = {"spring.cloud.service-registry.auto-registration.enabled"},
    matchIfMissing = true
)
@AutoConfigureAfter({AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class, NacosDiscoveryAutoConfiguration.class})
public class NacosServiceRegistryAutoConfiguration {
    public NacosServiceRegistryAutoConfiguration() {
    }

    @Bean
    public NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
        return new NacosServiceRegistry(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);
    }
}

可以看到服务注册类当中初始化了许多的 Bean 容器组件,这些组件都是 Spring 在初始化的时候注入到其中的,但以上 Bean 当中最核心的就是 NacosAutoServiceRegistration ,下面我们就 NacosAutoServiceRegistration 该类展开研究

注册的核心 NacosAutoServiceRegistration 类

先进入该类中大致的看一眼,该类的整体结构

image-20230412211052520

可以看到的是该类的构造方法调用的是父类的构造,传入了两个重要的参数,服务注册表 **serviceRegistry **与服务自动注册属性 autoServiceRegistrationProperties

image-20230412211605047

而父类将这两个注册的参数传递给当前的对象,这里的当前对象也就是在后端 yaml 中配置的相应信息,那么这些信息具体都是干什么都有什么作用呢?这就得去研究研究 NacosAutoSericeRegistration 这个类了,接着往下看。

NacosAutoSericeRegistration 的基础关系图

image-20230412213834501

从上面的图中可以 NacosAutoSericeRegistration 基础了抽象类 AbstractAutoServiceRegistrantion 同时该抽象类由实现了 ApplicationListener 这个接口,想必大家都知道 listener监听器是干什么的咯。同样的,这里的 ApplicationListener 也是同样的作用。

image-20230412214623037

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);

}

在监听接口当中有一个需要实现的方法 onApplicationEvent(E event) ,该方法是在项目启动时候会被触发的。

所以我们就返回其 AbstractAutoServiceRegistrantion 抽象类当中去看看该方法具体做了什么事呢?

@Override
@SuppressWarnings("deprecation")
public void onApplicationEvent(WebServerInitializedEvent event) {
	bind(event);
}
@Deprecated
public void bind(WebServerInitializedEvent event) {
	ApplicationContext context = event.getApplicationContext();
	if (context instanceof ConfigurableWebServerApplicationContext) {
		if ("management".equals(((ConfigurableWebServerApplicationContext) context)
				.getServerNamespace())) {
			return;
		}
	}
	this.port.compareAndSet(0, event.getWebServer().getPort());
	this.start();
}
public void start() {
	if (!isEnabled()) {
		if (logger.isDebugEnabled()) {
			logger.debug("Discovery Lifecycle disabled. Not starting");
		}
		return;
	}
	// only initialize if nonSecurePort is greater than 0 and it isn't already running
	// because of containerPortInitializer below
	if (!this.running.get()) {
		this.context.publishEvent(
				new InstancePreRegisteredEvent(this, getRegistration()));
        //注册
		register();
		if (shouldRegisterManagement()) {
			registerManagement();
		}
		this.context.publishEvent(
				new InstanceRegisteredEvent<>(this, getConfiguration()));
		this.running.compareAndSet(false, true);
	}
}

通过上面的代码可以看到在启动的瞬间先完成 WebServerInitializedEvent 服务器的一些初始化,然后其调用 start 方法中 完成随后的 register 完成注册。

image-20230412215731882

其实这里的 AbstractAutoServiceRegistranion 类下 register 调用最终是指向 AutoServiceRegistranion的 register 方法

@Override
public void register(Registration registration) {
	if (StringUtils.isEmpty(registration.getServiceId())) {
		log.warn("No service to register for nacos client...");
		return;
	}
	NamingService namingService = namingService();
	String serviceId = registration.getServiceId();
	String group = nacosDiscoveryProperties.getGroup();
    //构建instance实例
	Instance instance = getNacosInstanceFromRegistration(registration);
	try {
        //向服务端注册此服务
		namingService.registerInstance(serviceId, group, instance);
		log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
				instance.getIp(), instance.getPort());
	}
	catch (Exception e) {
		log.error("nacos registry, {} register failed...{},", serviceId,
				registration.toString(), e);
		// rethrow a RuntimeException if the registration is failed.
		// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
		rethrowRuntimeException(e);
	}
}

SpringBoot 项目-实例构建

private Instance getNacosInstanceFromRegistration(Registration registration) {
	Instance instance = new Instance();
	instance.setIp(registration.getHost());
	instance.setPort(registration.getPort());
	instance.setWeight(nacosDiscoveryProperties.getWeight());
	instance.setClusterName(nacosDiscoveryProperties.getClusterName());
	instance.setEnabled(nacosDiscoveryProperties.isInstanceEnabled());
	instance.setMetadata(registration.getMetadata());
	instance.setEphemeral(nacosDiscoveryProperties.isEphemeral());
	return instance;
}

Nacos源码提供的Dome - 实例构建

Instance instance = new Instance();
instance.setIp("1.1.1.1");
instance.setPort(800);
instance.setWeight(2);
Map<String, String> map = new HashMap<String, String>();
map.put("netType", "external");
map.put("version", "2.0");
instance.setMetadata(map);

image-20230412220513294

image-20230412220537115

image-20230412221048882

image-20230412221026761

哈哈~~~ 看到 AutoServiceRegistranion 类下的 register 方法大家有没有似曾相识的感觉呢?

没错这个和我之前在 Nacos 源码中的 registration 调用是一样的。

所以赖,通过上面的流程,对于 SpringBoot 项目中客户端实例的注册就立马明朗清晰了,下面要做什么呢?当然就是 Debug 验证我们的猜想咯。

补充 接口调用

**启动之前的项目测试类 9002 **

  • 可以看到项目在启动的瞬间先进行自动装载调用 NacosAutoServiceRegistration 方法,创建 NacosAutoServiceRegistration 对象

image-20230413134633695

  • 进入后调用父类的构造方法,然后给你属性赋值

image-20230413134823805

  • 随后会启用监听调用 bind 方法

image-20230413135341291

  • 调用其 start 方法

    image-20230413135833348

  • 通过 register 抽象方法交于我们的子类 实现

    image-20230413135937752

    image-20230413140114685

    image-20230413140245225

    • 这里就将我们的 SpringBoot 启动配置文件中的所有的信息,置入到了 instance 实例对象当中

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HB0PNcQj-1681367588116)(null)]

    • 前面看到 namingService 中调用了 registerInstance 方法进行注册,我们可以看看内部是怎么处理的

      image-20230413141058969

    • 其实这里内部也是通过代理的形式进行调用的,同时调用远端的一个 api 接口 /nacos/v1/ns/instance 进行注册,该接口也就是官方在官网中的文档中提到的 注册接口

      image-20230413141259666

      注册的本身是调用了 Nacos 的接口的,我们可以在官网上访问到的 Nacos

      image-20230413090350070

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/422230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4月Google Play政策更新,游戏上架需要注意这几点

3月21日&#xff0c;据路透社报道&#xff0c;由于发现国内某知名电商应用存在恶意软件问题&#xff0c;谷歌已暂时将该APP从商店下架&#xff0c;并表示&#xff1a;将该APP下架是一种安全预防措施&#xff0c;已经下载的用户也会收到警告&#xff0c;提示他们进行卸载。 4月…

基于深度学习的动物识别系统(YOLOv5清新界面版,Python代码)

摘要&#xff1a;动物识别系统用于识别和统计常见动物数量&#xff0c;通过深度学习技术检测日常几种动物图像识别&#xff0c;支持图片、视频和摄像头画面等形式。在介绍算法原理的同时&#xff0c;给出Python的实现代码、训练数据集以及PyQt的UI界面。动物识别系统主要用于常…

c/c++:算术运算符,赋值运算,逻辑运算,比较运算,三目运算,逗号运算,数据类型转换

c/c&#xff1a;算术运算符&#xff0c;赋值运算&#xff0c;逻辑运算&#xff0c;比较运算&#xff0c;三目运算&#xff0c;逗号运算&#xff0c;数据类型转换 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的…

【自定义表格穿梭框】自定义封装jqgrid表格穿梭框,支持分页复选全选(附完整源码及效果图)

【写在前面】其实之前业务中也有这个方面的需求&#xff0c;但是总觉得自己写的有点乱&#xff0c;此时也就借这个机会重新封装一个公共的函数去实现这个穿梭框的效果&#xff0c;支持分页勾选&#xff0c;页面展示已选中和未选择的数据&#xff0c;使得系统操作更友好。 涉及知…

数学建模(三):模拟退火算法(SA)

文章目录模拟退火算法&#xff08;SA&#xff09;一、 概述1、 算法简介2、 核心思想3、 数学原理4、 模拟退火的流程二、 实例分析1、 初始化参数2、 Metrospolis 准则3、 生成新的值4、 获取最优值5、 主程序6、 总代码模拟退火算法&#xff08;SA&#xff09; 一、 概述 1…

折叠屏市场起风,华为、OPPO“你追我赶”

配图来自Canva可画 现如今&#xff0c;智能手机已经成为了人们生活中不可或缺的重要工具&#xff0c;无论是出行&#xff0c;还是社交&#xff0c;亦或是支付&#xff0c;只需要一部智能手机就可以通通搞定。因此&#xff0c;在消费者多样化需求的助推下&#xff0c;智能手机行…

【Spring】—Spring中Bean的配置、作用域

一、Bean的配置 Spring用于生产和管理Spring容器中的Bean&#xff0c;需要开发者对Spring的配置文件进行配置。在实际开发中&#xff0c;最常采用XML格式的配置方式&#xff0c;即通过XML文件来注册并管理Bean之间的依赖关系。 在Spring中&#xff0c;XML配置文件的根元素是…

易基因:全基因组CpG密度和DNA甲基化分析方法比较(MeDIP、RRBS和WGBS)| 研究综述

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 CpG密度&#xff08;CpG density&#xff09;与各种组织中的DNA甲基化相关。基因组按CpG密度分为&#xff1a;CpG岛&#xff08;CpG island&#xff0c;CGI&#xff09;、CpG岛上下游2kb…

FFMPEG VCL Pack Crack显示位置支持或光标

FFMPEG VCL Pack Crack显示位置支持或光标 FFMPEG VCL Pack是一个组合解决方案和平台&#xff0c;用于在Delphi中录制、转换和传播音频和视频&#xff0c;其中包括音频/视频库中的前一个libavcodec。 FFMPEG VCL Pack功能和选项&#xff1a; 新的Live555公司基于Rtsp Media Ser…

基于深度学习的安全帽检测系统(YOLOv5清新界面版,Python代码)

摘要&#xff1a;安全帽检测系统用于自动化监测安全帽佩戴情况&#xff0c;在需要佩戴安全帽的场合自动安全提醒&#xff0c;实现图片、视频和摄像头等多种形式监测。在介绍算法原理的同时&#xff0c;给出Python的实现代码、训练数据集&#xff0c;以及PyQt的UI界面。安全帽检…

设计模式之迭代器模式(C++)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 一、迭代器模式是什么&#xff1f; 迭代器模式是一种行为型的软件设计模式&#xff0c;提供一种方法能顺序访问聚合对象中的各个元…

如何做好缓存设计?

大家好&#xff0c;我是易安&#xff01;今天我们来谈一谈缓存应该如何设计。 什么是缓存 缓存是一种临时储存数据的方式。当用户查询数据时&#xff0c;系统会首先在缓存中查找&#xff0c;如果数据已经存在于缓存中&#xff0c;则直接使用&#xff0c;否则系统会到数据的原始…

研报精选230410

目录 【行业230410西南证券】医药行业2023年4月投资月报&#xff1a;看好创新药和中药行情【行业230410国信证券】汽车行业4月投资策略&#xff1a;3月新能源乘用车批发销量预计同比增长32%&#xff0c;持续关注板块年报季报行情【行业230410西南证券】医药行业周报&#xff1a…

【集成架构】探索3种顶级「集成框架」Apache、Spring和Mule

正确的集成框架是绑定应用程序架构构建块的粘合剂。应用程序组件必须不断交换关键数据&#xff0c;以方便用户操作、服务扩展、威胁监视、后端操作、事件触发等。如果没有可靠的集成过程&#xff0c;应用程序和服务故障将淹没软件环境。正确的集成框架是绑定应用程序架构构建块…

【JAVA】#详细介绍!!! synchronized 加锁 详解(1)!

本文分以下几点来介绍synchronized&#xff08;根据JDK1.8&#xff09; 1. 介绍synchronized 2. synchronized 为什么能保证线程安全 3. synchronized 的 用法 4. synchronized 的锁特性 目录 1. 介绍synchronized 2. synchronized的用法 2.1 synchronized修饰指定代码块 2…

如何定位Spark数据倾斜问题,解决方案

文章目录前言一、数据倾斜和数据过量二、 数据倾斜的表现三、定位数据倾斜问题定位思路&#xff1a;查看任务-》查看Stage-》查看代码四、7种典型的数据倾斜场景解决方案一&#xff1a;聚合元数据解决方案二&#xff1a;过滤导致倾斜的key解决方案三&#xff1a;提高shuffle操作…

谁才是天下第一关?

什么是关&#xff0c;中华大地有多少关&#xff1f; 关是往来必由之要处。“山川扼要&#xff0c;是设关津。表封藏&#xff0c;以达道路&#xff0c;天险既呈&#xff0c;人力并济”。 关可分为&#xff1a; 关防&#xff0c;驻兵防守的要塞&#xff1b;关津&#xff0c;水陆…

python笔记:qgrid

在Jupyter Notebook中像在Excel一样操作pandas的DataFrames&#xff0c;如sort/filter&#xff0c;并轻松把操作后的数据用于后续分析。 0 安装 pip install qgrid jupyter nbextension enable --py --sys-prefix qgrid 1 基本使用方法 1.1 数据 import numpy as np import…

Carla 保姆级安装教程

一&#xff1a;电脑配置 carla支持windows,Linux系统构建&#xff0c;官方对于安装电脑的最低配置要求是拥有6G显存的GPU&#xff0c;推荐8G显存的GPU&#xff0c;至少需要20G的存储空间&#xff0c;所有对电脑的配置要求是不小的挑战。 我所使用电脑的硬件配置&#xff1a;3…

3.7 曲率

学习目标&#xff1a; 如果我要学习高等数学中的曲率&#xff0c;我会遵循以下步骤&#xff1a; 1.熟悉相关的数学概念&#xff1a;在学习曲率之前&#xff0c;我们需要了解曲线、切线和曲率半径等相关的数学概念。因此&#xff0c;我会复习这些概念&#xff0c;以便更好地理…