springcloudAlibaba之Nacos服务注册源码分析

news2024/11/20 20:39:28

Nacos服务注册源码分析

  • Nacos服务注册原理
  • Nacos服务注册怎么做的
  • Nacos服务注册源码解读

带着以上三个问题,进入到今天的源码解读

问题1:Nacos服务注册原理

Nacos首先从bootstrap.yml配置文件中读取我们配置好的nacos配置,这里面一般包括spring.application.name、spring.cloud.nacos.discovery.server-addr、spring.cloud.nacos.username、spring.cloud.nacos.password以及其他的一些例如cluster、namespace等信息,依托ConfigurationProperties注解 让spring将这些配置封装成一个对象,在容器刷新完成之后执行一个register方法,把当前应用注册到指定的Nacos服务端

问题2:Nacos服务注册怎么做的

我们知道 像这种第三方集成springboot的应用,一般都会使用starter封装起来,而starter的核心就是自动装配,那么我们只需要搜索类似nacosAutoconfig之类的 就应该可以找到

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不出所料 我们成功搜索到了几个类,大致可以分为三类 config配置中心、discovery注册中心以及ribbon负载均衡 ,目前我们关注的是注册中心 那么直接选择NacosDiscoveryAutoConfiguration即可。

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

    @Bean
    public NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
        return new NacosServiceRegistry(nacosDiscoveryProperties);
    }

    @Bean
    @ConditionalOnBean({AutoServiceRegistrationProperties.class})
    public NacosRegistration nacosRegistration(NacosDiscoveryProperties nacosDiscoveryProperties, ApplicationContext context) {
        return new NacosRegistration(nacosDiscoveryProperties, context);
    }

    @Bean
    @ConditionalOnBean({AutoServiceRegistrationProperties.class})
    public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
        return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration);
    }
}

通过观察这个类 可以看出来它是一个典型的springboot配置类,它里面干了三件事,也可以说是一件事,那就是注册Bean,第一、第二个bean是第三个bean的入参 ,说明第三个bean是重点,点进去之后发现这个类里面有一个register方法,盲猜 这个应该就是用来注册的方法,registration对象就是我们配置文件中的配置信息

    public void register(Registration registration) {
        if (StringUtils.isEmpty(registration.getServiceId())) {
            log.warn("No service to register for nacos client...");
        } else {
            String serviceId = registration.getServiceId();
            Instance instance = new Instance();
            instance.setIp(registration.getHost());
            instance.setPort(registration.getPort());
            instance.setWeight((double)this.nacosDiscoveryProperties.getWeight());
            instance.setClusterName(this.nacosDiscoveryProperties.getClusterName());
            instance.setMetadata(registration.getMetadata());

            try {
                this.namingService.registerInstance(serviceId, instance);
                ...
            } catch (Exception var5) {
                ...
            }

        }
    }

那么是谁来调用这个register方法呢?这个我们后面再说。回到NacosDiscoveryAutoConfiguration类,这里面有几个注解需要关注,这几个注解定义了这个类执行的前提条件

@Configuration  #声明这是一个springboot配置类
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled#条件注解:只有NacosDiscoveryEnabledtrue时 这个类才生效
@ConditionalOnProperty(value = {"spring.cloud.service-registry.auto-registration.enabled"},
     				   matchIfMissing = true
                     )#和上面一样 只有配置文件中enabled为true时 这个类才生效 默认为true 如何使用其他框架例如dubbo进行服务注册 需要把这个设为false 要不然就会注册两个相同的服务
@AutoConfigureAfter({AutoServiceRegistrationConfiguration.class,
                     AutoServiceRegistrationAutoConfiguration.class})#声明需要在这两个bean创建之后进行加载
    
@ConditionalOnBean({AutoServiceRegistrationProperties.class})#容器中存在这个bean才会生效

问题3:Nacos服务注册源码解读

通过第二步的探究,我们锁定了register这个方法,那么是由谁来调用它的呢?

通过debug的方式 我们从控制台看到了这样的堆栈信息

在这里插入图片描述

通过堆栈信息可以清楚的看出来 它是从spring核心方法refresh方法中的finishRefresh方法进入的,它的大致链路就是refresh–>finishRefresh–>this.getLifecycleProcessor().onRefresh()–>startBeans(这个方法有一个while循环 当beanName是webServerStartStop时 走到下面链路)

–>((DefaultLifecycleProcessor.LifecycleGroup)phases.get(key)).start()

–>DefaultLifecycleProcessor.this.doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);

–>this.doStart(lifecycleBeans, dependency, autoStartupOnly);

–>bean.start()

–>this.applicationContext.publishEvent(new ServletWebServerInitializedEvent(this.webServer, this.applicationContext));

–>this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);

–>this.invokeListener(listener, event);

–this.doInvokeListener(listener, event);

–>listener.onApplicationEvent(event);

–>AbstractAutoServiceRegistration.onApplicationEvent.this.bind(event)

–this.start()

–this.register();

–this.serviceRegistry.register(this.getRegistration());

Nacos巧妙的运用springboot提供的事件订阅和发布机制,使得springboot应用在容器启动完成后第一时间调用register方法 将当前应用信息作为服务注册到nacos服务端

总结

首先springboot应用启动时会自动加载一个beanNamewebServerStartStop,这个bean对应的类是WebServerStartStopLifecycle,这个类又实现了SmartLifecycle这个接口,关于lifecycle接口的解释,借用网上的一段话

Lifecycle是Spring中最基础的生命周期接口,该接口定义了容器启动和停止的方法。方便开发者扩展自己的特定逻辑,比如启动和停止某些后台进程。Lifecycle常用来管理一个组件的启动和停止,可能会有这样的疑惑:开始和停止的逻辑写在一个bean的初始化方法和销毁方法中不可以了吗,为什么要实现个Lifecycle接口呢?这里说明一下,bean的初始化方法和销毁方法是Bean生命周期级别的;而Lifecycle是容器生命周期级别的。

它的意思就是 只有当容器启动和关闭的时候 ,springboot应用才会调用实现了这些接口的类

当我们context刷新成功之后会调用finishRefresh方法

protected void finishRefresh() {
    this.clearResourceCaches();
    this.initLifecycleProcessor();#在这里把所有实现了lifecycle的bean进行加载
    this.getLifecycleProcessor().onRefresh();#在这里把上面加载好的bean一一执行
    this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
    LiveBeansView.registerApplicationContext(this);
}

里面就有一个WebServerStartStopLifecycle这个bean,按照设定 会去调用这个bean的start方法

public void start() {
    this.webServer.start();
    this.running = true;
    this.applicationContext.publishEvent(
        new ServletWebServerInitializedEvent(this.webServer, this.applicationContext));
}

这里关键的是最后的publishEvent方法,它会去发布一个事件,并将满足条件的监听器进行依次执行,从代码中可以看出 只要是ServletWebServerInitializedEvent相关的且实现了ApplicationListener的类 都会被执行,而ServletWebServerInitializedEvent又是WebServerInitializedEvent的子类,换句话讲 只要是WebServerInitializedEvent相关的类 都会被执行。

巧合的是AbstractAutoServiceRegistration这个类实现了ApplicationListener,并且入参泛型就是WebServerInitializedEvent,那么一定会执行到这个类中的方法。那么这个类是哪来的呢?回到最上面自动装配的那块,nacos自动装配的3个bean,其中最后一个beanNacosAutoServiceRegistration的父类就是AbstractAutoServiceRegistration

在执行满足条件的监听器方法时,会调用onApplicationEvent方法,然后到bind方法、start方法,最终在start方法中调用this.register()方法,调用的就是ServiceRegistryregister方法,而当前应用有且只有一个ServiceRegistry的实现类,就是NacosServiceRegistry,最终成功执行register方法,至此 nacos成功注册。

public abstract class AbstractAutoServiceRegistration<R extends Registration> implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {
    private static final Log logger = LogFactory.getLog(AbstractAutoServiceRegistration.class);
    private final ServiceRegistry<R> serviceRegistry;
    private boolean autoStartup = true;
    private AtomicBoolean running = new AtomicBoolean(false);
    private int order = 0;
    private ApplicationContext context;
    private Environment environment;
    private AtomicInteger port = new AtomicInteger(0);
    private AutoServiceRegistrationProperties properties;

    protected void register() {
        this.serviceRegistry.register(this.getRegistration());
    }
    
    public void onApplicationEvent(WebServerInitializedEvent event) {
        this.bind(event);
    }
    /** @deprecated */
    @Deprecated
    public void bind(WebServerInitializedEvent event) {
        ApplicationContext context = event.getApplicationContext();
        if (!(context instanceof ConfigurableWebServerApplicationContext) || !"management".equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) {
            this.port.compareAndSet(0, event.getWebServer().getPort());
            this.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.register();
                if (this.shouldRegisterManagement()) {
                    this.registerManagement();
                }

                this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));
                this.running.compareAndSet(false, true);
            }

        }
        ........
    }
}

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

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

相关文章

亚马逊,速卖通,国际站卖家如何找到真实干净的买家账号测评补单

对于卖家而言&#xff0c;测评资源确实是一项宝贵的财富。通过自养号和广告相结合的策略&#xff0c;可以快速有效地提升产品销量、增加转化率以及提高Listing的权重。这是一个很好的方法来优化产品在平台上的表现 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&…

小谈设计模式(18)—适配器模式

小谈设计模式&#xff08;18&#xff09;—适配器模式 专栏介绍专栏地址专栏介绍 适配器模式角色分析目标接口&#xff08;Target&#xff09;源接口&#xff08;Adaptee&#xff09;适配器&#xff08;Adapter&#xff09; 核心思想应用场景Java程序实现输出结果程序分析123 优…

【Python】基于OpenCV人脸追踪、手势识别控制的求生之路FPS游戏操作

【Python】基于OpenCV人脸追踪、手势识别控制的求生之路FPS游戏操作 文章目录 手势识别人脸追踪键盘控制整体代码附录&#xff1a;列表的赋值类型和py打包列表赋值BUG复现代码改进优化总结 py打包 视频&#xff1a; 基于OpenCV人脸追踪、手势识别控制的求实之路FPS游戏操作 手…

两文学会scala (下)|保姆级别教程(超详细)

上文内容概括&#xff1a; Scala 概述与安装、变量、运算符、流程控制、函数式编程、面向对象 上文链接&#xff1a;两文学会scala &#xff08;上&#xff09;&#xff5c;保姆级别教程&#xff08;超详细&#xff09;_超爱慢的博客-CSDN博客 目录 第7章 集合 7.1 集合简介…

增强负样本提高CPI表现

确定CPI对药物发现至关重要。由于实验验证CPI通常是耗时和昂贵的&#xff0c;计算方法有望促进这一过程。可用CPI数据库的快速增长加速了许多用于CPI预测的机器学习方法发展。然而&#xff0c;它们的性能&#xff0c;特别是它们对外部数据的泛化性&#xff0c;经常受到数据不平…

根据您的数据量定制的ChatGPT,改变客户服务的方式

在当今竞争激烈的商业环境中&#xff0c;提供优质的客户服务对于保持忠诚的客户群和推动业务增长至关重要。客户满意度已成为各行各企业的首要任务&#xff0c;因为它直接影响客户留存和品牌声誉。随着技术的进步&#xff0c;公司不断探索创新解决方案&#xff0c;以增强客户服…

Mac 挂载 Alist网盘

挂载服务器的Alist 网盘到 Mac mac,使用的是 CloundMounter 这个软件进行挂载 http://ip:port/dav/ 需要在末尾加上 /dav/ 在一些服务器上&#xff0c;为了提供WebDAV服务&#xff0c;需要在URL地址的末尾添加"/dav/“。这是因为WebDAV协议规定了一些标准的URL路径&#x…

1024 科学计数法

一.问题&#xff1a; 科学计数法是科学家用来表示很大或很小的数字的一种方便的方法&#xff0c;其满足正则表达式 [-][1-9].[0-9]E[-][0-9]&#xff0c;即数字的整数部分只有 1 位&#xff0c;小数部分至少有 1 位&#xff0c;该数字及其指数部分的正负号即使对正数也必定明确…

SpringBoot的流浪宠物系统

采用技术:springbootvue 项目可以完美运行

数控车床中滚珠螺母的维护保养方法

滚珠螺母是一种高精度的机械部件&#xff0c;广泛应用于各种机械设备中&#xff0c;包括数控机床、精密轴承座、滚珠丝杆等&#xff0c;滚珠螺母作为数控机床中的进给系统的重要组件&#xff0c;其维护保养方法对于机床的精度和使用寿命具有重要影响。以下为数控机床滚珠螺母维…

1800_vim的宏录制功能尝试

全部学习信息汇总&#xff1a; GreyZhang/editors_skills: Summary for some common editor skills I used. (github.com) 最近5年多来&#xff0c;我emacs的编辑器用的还是比较多的。我的配置基本上是一个spacemacs&#xff0c;然后根据自己的需求增加了一丁点儿的其他配置。而…

数据结构基本概念-Java常用算法

数据结构基本概念-Java常用算法 1、数据结构基本概念2、数据逻辑结构3、算法时间复杂度 1、数据结构基本概念 数据&#xff08;Data&#xff09;&#xff1a;数据是信息的载体&#xff0c;其能够被计算机识别、存储和加工处理&#xff0c;是计算机程序加工的“原材料”。数据元…

C++stackqueue

目录 一、stack 1.1 简要介绍 1.2 小试身手 1.3 模拟实现 二、queue 2.1 简要介绍 2.2 小试身手 2.3 模拟实现 三、deque 3.1 简要介绍 3.2 分析底层 四、priority_queue 4.1 简要介绍 4.2 小试身手 4.3 模拟实现 五、仿函数/函数对象 5.1 简要介绍 一…

全网最全Python系列教程(非常详细)---Python中文乱码讲解(学Python入门必收藏)

&#x1f9e1;&#x1f9e1;&#x1f9e1;这篇是关于Python中为什么会出现中文乱码的讲解&#xff0c;欢迎点赞和收藏&#xff0c;你点赞和收藏是我更新的动力&#x1f9e1;&#x1f9e1;&#x1f9e1; 在解释Python中中文乱码的问题之前&#xff0c;我们先对计算机中几个基本…

物联网AI MicroPython传感器学习 之 手指侦测心跳传感器

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; 一、产品简介 手指侦测心跳传感器是通过LED和光电晶体管监测手指血压脉冲&#xff0c;来判断人的心脏跳动。其结构简单成本低廉&#xff0c;只能是做一些实验和学习相关的知识&#xff08;没有医疗实用价值&…

C++11新特性(语法糖,新容器)

距离C11版本发布已经过去那么多年了&#xff0c;为什么还称为新特性呢&#xff1f;因为笔者前面探讨的内容&#xff0c;除了auto&#xff0c;范围for这些常用的&#xff0c;基本上是用着C98的内容&#xff0c;虽说C11已经发布很多年&#xff0c;却是目前被使用最广泛的版本。因…

string类的模拟实现(万字讲解超详细)

目录 前言 1.命名空间的使用 2.string的成员变量 3.构造函数 4.析构函数 5.拷贝构造 5.1 swap交换函数的实现 6.赋值运算符重载 7.迭代器部分 8.数据容量控制 8.1 size和capacity 8.2 empty 9.数据修改部分 9.1 push_back 9.2 append添加字符串 9.3 运算符重载…

Nacos与Eureka的区别

大家好我是苏麟今天说一说Nacos与Eureka的区别. Nacos Nacos的服务实例分为两种l类型&#xff1a; 临时实例&#xff1a;如果实例宕机超过一定时间&#xff0c;会从服务列表剔除&#xff0c;默认的类型。非临时实例&#xff1a;如果实例宕机&#xff0c;不会从服务列表剔除&…

Python安装指南:安装Python、配置Python环境(附安装包)

1. 选择正确的版本&#xff0c;下载安装包 根据你的实际需要选择Python发行版本。 值得注意的是&#xff0c;编程语言包并不是越新越好的&#xff0c;不同版本的Python之间可能会产生兼容性问题。 如果你不确定你的项目需要哪个版本&#xff0c;请查阅您可能需要使用到的插件的…

输入电压转化为电流性 5~20mA方案

输入电压转化为电流性 5~20mA方案 方案一方案二方案三 方案一 XTR111是一款精密的电压-电流转换器是最广泛应用之一。原因有二&#xff1a;一是线性度非常好、二是价格便宜。总结成一点&#xff0c;就是性价比高。 典型电路 最终电路 Z1二极管处输出电流表达式&#xff1a;…