8、Nacos服务注册服务端源码分析(七)

本文收录于专栏 Nacos 中 。

文章目录

  • 前言
  • 确定前端路由
  • CatalogController.listDetail()
  • ServiceManager
  • 总结


前言

前文我们分析了Nacos中客户端注册时数据分发的设计链路,本文根据Nacos前端页面请求,看下前端页面中的服务列表的数据源于哪里。

确定前端路由

我们已经向Nacos中注册了一个服务,现在去前端确定查询的路由是什么
在这里插入图片描述
确定前端请求路由:/nacos/v1/ns/catalog/services
通过路由确定后端代码位置:

package com.alibaba.nacos.naming.controllers;
CatalogController.listDetail()

CatalogController.listDetail()

/*** List service detail information.** @param withInstances     whether return instances* @param namespaceId       namespace id* @param pageNo            number of page* @param pageSize          size of each page* @param serviceName       service name* @param groupName         group name* @param containedInstance instance name pattern which will be contained in detail* @param hasIpCount        whether filter services with empty instance* @return list service detail*/
@Secured(action = ActionTypes.READ)
@GetMapping("/services")
public Object listDetail(@RequestParam(required = false) boolean withInstances,@RequestParam(defaultValue = Constants.DEFAULT_NAMESPACE_ID) String namespaceId,@RequestParam(required = false) int pageNo, @RequestParam(required = false) int pageSize,@RequestParam(name = "serviceNameParam", defaultValue = StringUtils.EMPTY) String serviceName,@RequestParam(name = "groupNameParam", defaultValue = StringUtils.EMPTY) String groupName,@RequestParam(name = "instance", defaultValue = StringUtils.EMPTY) String containedInstance,@RequestParam(required = false) boolean hasIpCount) throws NacosException {//前端withInstances传的是false,不走这个分支if (withInstances) {return judgeCatalogService().pageListServiceDetail(namespaceId, groupName, serviceName, pageNo, pageSize);}//确定是走的这里获取的服务列表return judgeCatalogService().pageListService(namespaceId, groupName, serviceName, pageNo, pageSize, containedInstance, hasIpCount);
}

查看judgeCatalogService().pageListService(namespaceId, groupName, serviceName, pageNo, pageSize, containedInstance, hasIpCount);的实现:

@Override
public Object pageListService(String namespaceId, String groupName, String serviceName, int pageNo, int pageSize,String instancePattern, boolean ignoreEmptyService) throws NacosException {ObjectNode result = JacksonUtils.createEmptyJsonNode();List<ServiceView> serviceViews = new LinkedList<>();//获取服务列表Collection<Service> services = patternServices(namespaceId, groupName, serviceName);if (ignoreEmptyService) {services = services.stream().filter(each -> 0 != serviceStorage.getData(each).ipCount()).collect(Collectors.toList());}result.put(FieldsConstants.COUNT, services.size());services = doPage(services, pageNo - 1, pageSize);for (Service each : services) {ServiceMetadata serviceMetadata = metadataManager.getServiceMetadata(each).orElseGet(ServiceMetadata::new);ServiceView serviceView = new ServiceView();serviceView.setName(each.getName());serviceView.setGroupName(each.getGroup());serviceView.setClusterCount(serviceStorage.getClusters(each).size());serviceView.setIpCount(serviceStorage.getData(each).ipCount());serviceView.setHealthyInstanceCount(countHealthyInstance(serviceStorage.getData(each)));serviceView.setTriggerFlag(isProtectThreshold(serviceView, serviceMetadata) ? "true" : "false");serviceViews.add(serviceView);}result.set(FieldsConstants.SERVICE_LIST, JacksonUtils.transferToJsonNode(serviceViews));return result;
}private Collection<Service> patternServices(String namespaceId, String group, String serviceName) {boolean noFilter = StringUtils.isBlank(serviceName) && StringUtils.isBlank(group);if (noFilter) {//我们前端默认传的这两个参数都是空,所以会走这里的逻辑return ServiceManager.getInstance().getSingletons(namespaceId);}Collection<Service> result = new LinkedList<>();StringJoiner regex = new StringJoiner(Constants.SERVICE_INFO_SPLITER);regex.add(getRegexString(group));regex.add(getRegexString(serviceName));String regexString = regex.toString();for (Service each : ServiceManager.getInstance().getSingletons(namespaceId)) {if (each.getGroupedServiceName().matches(regexString)) {result.add(each);}}return result;
}

ServiceManager.getInstance()这里一看就是一个经典的单例写法,那我们接下来把精力放到getSingletons这个方法上。
namespaceId默认是public

ServiceManager

public Set<Service> getSingletons(String namespace) {return namespaceSingletonMaps.getOrDefault(namespace, new HashSet<>(1));
}

通过代码我们发现,获取制定namespace下的服务是从一个map中获取的。

/*** Nacos service manager for v2.** @author xiweng.yy*/
public class ServiceManager {private static final ServiceManager INSTANCE = new ServiceManager();private final ConcurrentHashMap<Service, Service> singletonRepository;private final ConcurrentHashMap<String, Set<Service>> namespaceSingletonMaps;//...
}

我们可以发现ServiceManager这个类是一个单例模式的实现,其中维护了两个map,其中一个namespaceSingletonMaps用于存放制定namespace下的服务,那么这个map中的数据是在什么时机存放进去的呢?

/**1. Get singleton service. Put to manager if no singleton.2.  3. @param service new service4. @return if service is exist, return exist service, otherwise return new service*/
public Service getSingleton(Service service) {singletonRepository.computeIfAbsent(service, key -> {NotifyCenter.publishEvent(new MetadataEvent.ServiceMetadataEvent(service, false));return service;});Service result = singletonRepository.get(service);namespaceSingletonMaps.computeIfAbsent(result.getNamespace(), namespace -> new ConcurrentHashSet<>());namespaceSingletonMaps.get(result.getNamespace()).add(result);return result;
}

观察代码我们发现,往map中写数据的只有这一个方法,那么这个方法是在什么时机被调用的呢?
我们重新梳理之前客户端注册的部分逻辑:

  1. InstanceRequestHandler接收所有实例注册、注销相关的请求
  2. InstanceRequestHandler处理注册请求时,会调用EphemeralClientOperationServiceImpl中的registerInstance方法
  3. registerInstance方法中除了我们之前讲的发布客户端服务注册事件ClientOperationEvent.ClientRegisterServiceEvent之外,还会往ServiceManager中的map添加数据

registerInstance方法对ServiceManager的处理逻辑如下:

Service singleton = ServiceManager.getInstance().getSingleton(service);

总结

通过以上梳理,我们知道了前端服务列表中获取的数据是源于ServiceManager类中一个map的缓存,缓存中的数据是在客户端服务注册时添加进去的。

先梳理脉络,然后以点到面,一切都会逐渐清晰。

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

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

相关文章

【数据结构】红黑树(C++实现)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【数据…

Windows + Git + TortoiseGit + Github

一、下载Git&#xff08;Git For Windows&#xff09; 1.1. Git下载地址&#xff1a;https://gitforwindows.org/ 1.2. 默认安装即可&#xff08;包名&#xff1a;Git-2.42.0.2-64-bit.exe&#xff09; 二、下载TortoiseGit 2.1.TortoiseGit下载地址&#xff1a;http://tortoi…

类加载机制

类加载运行全过程 当我们用java命令运行某个类的main函数启动程序时&#xff0c;首先需要通过类加载器把主类加载到 JVM。 public class Math {public static final int initData 666;public static User user new User();public int compute() { //一个方法对应一块栈帧内…

CSS的基础

CSS美化HTML&#xff0c;布局网页 CSS最大的价值&#xff1a;由HTML专注去做结构呈现&#xff0c;样式给CSS&#xff0c;结构&#xff08;HTML)与样式&#xff08;CSS&#xff09;相分离 CSS主要由选择器以及一条或多条声明 在<head></head>中实现CSS在<body…

Docker部署Nginx-常用命令

1.拉取 docker pull nginx 2. 查看镜像 docker images 3.保存镜像 docker save -o nginx.tar nginx:latest 4.删除镜像 docker rmi nginx:latest 5. 加载镜像 docker load -i nginx.tar 6. 运行Nginx docker run -d --name nginx -p 80:80 nginx 7.停掉Nginx容器 docker stop n…

Blender 导出 fbx 到虚幻引擎中丢失材质!!!(使用Blender导出内嵌材质的fbx即可解决)

目录 0 引言1 Blender导出内嵌纹理的fbx模型 0 引言 我在Blender处理了一些fbx模型后再次导出到UE中就经常出现&#xff0c;材质空白的情况&#xff08;如下图所示&#xff09;&#xff0c;今天终于找到问题原因&#xff0c;记录下来&#xff0c;让大家避免踩坑。 其实原因很简…

弧度、圆弧上的点、圆的半径(r)、弧长(s)之间的关系

要计算弧度和圆弧上的点&#xff0c;需要知道以下几个要素&#xff1a; 圆的半径&#xff08;r&#xff09;&#xff1a;即圆的中心到圆周上任意一点的距离。 弧长&#xff08;s&#xff09;&#xff1a;从圆周上的一个点到另一个点所经过的弧长。 弧度&#xff08;θ&#x…

【chainlit】使用chainlit部署chatgpt

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

HCQ1-1300-D【高速输入】

因为我的PLC固件比较旧。所以有些限制。【比如&#xff1a;编译不报错&#xff0c;下载PLC程序就报故障】我的PLC的高速输入类型只能是【hsi_ref】 所以&#xff0c;程序添加的高速输入模块只能是【1.0.1.0】版本 如果固件版本低&#xff0c;看下固件能支持的类型。选错的话&am…

centos安装conda python3.10

最新版本的conda自带python3.10,直接安装即可。 手动创建一个conda文件夹&#xff0c;进入该文件夹&#xff0c;然后执行以下操作步骤。 1.下载 curl -O https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh2.安装 sh Miniconda3-latest-Linux-x86_64.…

串口数据包收发

数据包 把属于同一批的数据进行打包和分割&#xff0c;方便接收方进行识别 HEX数据包 思路&#xff1a;一个数据规定四个字节&#xff0c;以0xFF为包头&#xff0c;0xFE为包尾&#xff0c;当检测到0xFF时&#xff0c;接下来四个数据就是数据&#xff0c;接收到0xFE时&#x…

FFMPEG 视频类过滤器学习整理

addroi 作用 在视频帧上标记一块感兴趣的区域。 帧数据被原封不动地传递&#xff0c;但元数据被附加到帧&#xff0c;指示可能影响后续编码行为的感兴趣区域。可以通过多次应用过滤器来标记多个区域。 参数 qoffset: 应用在此区域的量化偏移。 参数范围&#xff1a;-1 ~ …

【JVM】第五篇 垃圾收集器G1和ZGC详解

导航 一. G1垃圾收集算法详解1. 大对象Humongous说明2. G1收集器执行一次GC运行的过程步骤3. G1垃圾收集分类4. G1垃圾收集器参数设置5. G1垃圾收集器的优化建议6. 适合使用G1垃圾收集器的场景?二. ZGC垃圾收集器详解1. NUMA与UMA2. 颜色指针3. ZGC的运作过程4. ZGC垃圾收集器…

开发中的前端和后端

一、引言 前端和后端是Web开发中两个不同的领域。 前端开发主要负责实现用户界面的设计和功能&#xff0c;包括网页的布局、样式和交互效果。前端开发使用HTML、CSS和JavaScript等技术来构建用户在浏览器中直接与之交互的界面。前端开发人员需要关注网页的可视化效果和用户体验…

【软件测试】自动化测试selenium(一)

文章目录 一. 什么是自动化测试二. Selenium的介绍1. Selenium是什么2. Selenium的特点3. Selenium的工作原理4. SeleniumJava的环境搭建 一. 什么是自动化测试 自动化测试是指使用软件工具或脚本来执行测试任务的过程&#xff0c;以替代人工进行重复性、繁琐或耗时的测试活动…

MySQL进阶_查询优化和索引优化

文章目录 第一节、索引失效案例1.1 数据准备1.2 全值匹配我最爱1.3 最佳左前缀法则 第一节、索引失效案例 可以从以下维度对数据库进行优化&#xff1a; 索引失效、没有充分利用到索引–索引建立关联查询太多JOIN (设计缺陷或不得已的需求)–SQL优化服务器调优及各个参数设置…

排序算法之【希尔排序】

&#x1f4d9;作者简介&#xff1a; 清水加冰&#xff0c;目前大二在读&#xff0c;正在学习C/C、Python、操作系统、数据库等。 &#x1f4d8;相关专栏&#xff1a;C语言初阶、C语言进阶、C语言刷题训练营、数据结构刷题训练营、有感兴趣的可以看一看。 欢迎点赞 &#x1f44d…

[管理与领导-112]:IT人看清职场中的隐性规则 - 9 - 付出与回报的关系:先付出,后回报,不行就止损,这才是职场价值交换的本质

目录 一、职场中付出与回报的先后关系 二、付出与回报四象限模型 三、职场专业性的本质 一、职场中付出与回报的先后关系 在职场中&#xff0c;个人的付出和回报之间存在着先后关系。以下是按照先后关系划分的四种类型&#xff1a; 先付出后回报型&#xff0c;不回报&#…

【数据结构和算法】--N叉树中,返回某些目标节点到根节点的所有路径

目录 一、前言二、具体实现及拓展2.1、递归-目标节点到根节点的路径数据2.2、list转换为tree结构2.3、tree转换为list结构 一、前言 这么多年工作经历中&#xff0c;“数据结构和算法”真的是超重要&#xff0c;工作中很多业务都能抽象成某种数据结构问题。下面是项目中遇到的…

华为云云耀云服务器L实例评测|云耀云服务器L实例部署Gogs服务器

华为云云耀云服务器L实例评测&#xff5c;云耀云服务器L实例部署Gogs服务器 一、云耀云服务器L实例介绍1.1 云耀云服务器L实例简介1.2 云耀云服务器L实例特点 二、Gogs介绍2.1 Gogs简介2.2 Gogs特点 三、本次实践介绍3.1 本次实践简介3.2 本次环境规划 四、远程登录华为云云耀云…