一个Spring Boot Admin 监控多个Nacos集群

背景

我们有多个系统,每个系统一个集群,每个集群都部署了自己的Spring Boot Admin(以下简称Admin),用起来不仅不方便,私有化部署的时候还得多部署几个服务,为了解决这个问题,我想到了是否可以用一个Admin同时监控多个集群,这里集群指监控Nacos集群。

实现

通过查看Nacos的服务注册源码、Admin监控的服务发现源码,最终得出结论:重写NacosServiceManager、NamingService类,即可实现。

  • 为了监控多个Namespace,nacos的服务发现配置通过分号分割即可
  • 为了区别与原来只能订阅单个Namespace,将所有的重写类定义为Multixxx
  • 将自定义的MultiNacosServiceManager类定义为主要Bean

MultiNacosServiceManager
这个类用来管理NamingService,包括创建NamingService,NamingMaintainService。

import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingMaintainService;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.client.naming.NacosNamingService;
import org.apache.commons.lang3.SerializationUtils;import java.util.*;import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;public class MultiNacosServiceManager extends NacosServiceManager {//namespace分隔符public static final String SEMICOLON = ";";private MultiNacosNamingService multiNacosNamingService;@Overridepublic NamingService getNamingService(Properties properties) {if (Objects.isNull(this.multiNacosNamingService)) {multiNacosNamingService = buildNamingService(properties);}return multiNacosNamingService;}//这个服务就只取第一个了,简单点@Overridepublic NamingMaintainService getNamingMaintainService(Properties properties) {String namespace = properties.getProperty(NAMESPACE);if (namespace.contains(SEMICOLON)) {String[] namespaces = namespace.split(";");properties.setProperty(NAMESPACE, namespaces[0]);}return super.getNamingMaintainService(properties);}private MultiNacosNamingService buildNamingService(Properties properties) {if (Objects.isNull(multiNacosNamingService)) {synchronized (MultiNacosServiceManager.class) {if (Objects.isNull(multiNacosNamingService)) {try {String namespace = properties.getProperty(NAMESPACE);if (namespace.contains(SEMICOLON)) {List<NacosNamingService> multiNacosNamingService = new ArrayList<>();//每个namespace创建一个namingServicefor (String ns : namespace.split(SEMICOLON)) {Properties newProperties = SerializationUtils.clone(properties);newProperties.setProperty(NAMESPACE, ns);NacosNamingService namingService = (NacosNamingService) NacosFactory.createNamingService(newProperties);multiNacosNamingService.add(namingService);}return new MultiNacosNamingService(multiNacosNamingService);} else {NacosNamingService namingService = (NacosNamingService) NacosFactory.createNamingService(properties);return new MultiNacosNamingService(Collections.singletonList(namingService));}} catch (NacosException e) {throw new RuntimeException(e);}}}}return multiNacosNamingService;}
}

MultiNacosNamingService
将多个 nacosNamingService 组合为一个对外提供服务,原有的NamingService 只支持单个namespace,将原来有NamingService方法都重写为支持多个namespace。

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import com.alibaba.nacos.api.naming.pojo.ServiceInfo;
import com.alibaba.nacos.api.selector.AbstractSelector;
import com.alibaba.nacos.client.naming.NacosNamingService;import java.util.ArrayList;
import java.util.List;import static de.codecentric.boot.admin.server.domain.values.StatusInfo.STATUS_DOWN;
import static de.codecentric.boot.admin.server.domain.values.StatusInfo.STATUS_UP;/*** 将多个 nacosNamingService 组合为一个对外提供服务*/
public class MultiNacosNamingService implements NamingService {private List<NacosNamingService> nacosNamingServices;public MultiNacosNamingService(List<NacosNamingService> nacosNamingServices) {this.nacosNamingServices = nacosNamingServices;}@Overridepublic void registerInstance(String serviceName, String ip, int port) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.registerInstance(serviceName, ip, port);}}@Overridepublic void registerInstance(String serviceName, String groupName, String ip, int port) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.registerInstance(serviceName, groupName, ip, port);}}@Overridepublic void registerInstance(String serviceName, String ip, int port, String clusterName) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.registerInstance(serviceName, ip, port, clusterName);}}@Overridepublic void registerInstance(String serviceName, String groupName, String ip, int port, String clusterName) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.registerInstance(serviceName, groupName, ip, port, clusterName);}}@Overridepublic void registerInstance(String serviceName, Instance instance) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.registerInstance(serviceName, instance);}}@Overridepublic void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.registerInstance(serviceName, groupName, instance);}}@Overridepublic void deregisterInstance(String serviceName, String ip, int port) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.deregisterInstance(serviceName, ip, port);}}@Overridepublic void deregisterInstance(String serviceName, String groupName, String ip, int port) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.deregisterInstance(serviceName, groupName, ip, port);}}@Overridepublic void deregisterInstance(String serviceName, String ip, int port, String clusterName) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.deregisterInstance(serviceName, ip, port, clusterName);}}@Overridepublic void deregisterInstance(String serviceName, String groupName, String ip, int port, String clusterName) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.deregisterInstance(serviceName, groupName, ip, port, clusterName);}}@Overridepublic void deregisterInstance(String serviceName, Instance instance) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.deregisterInstance(serviceName, instance);}}@Overridepublic void deregisterInstance(String serviceName, String groupName, Instance instance) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.deregisterInstance(serviceName, groupName, instance);}}@Overridepublic List<Instance> getAllInstances(String serviceName) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.getAllInstances(serviceName));}return instances;}@Overridepublic List<Instance> getAllInstances(String serviceName, String groupName) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.getAllInstances(serviceName, groupName));}return instances;}@Overridepublic List<Instance> getAllInstances(String serviceName, boolean subscribe) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.getAllInstances(serviceName, subscribe));}return instances;}@Overridepublic List<Instance> getAllInstances(String serviceName, String groupName, boolean subscribe) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.getAllInstances(serviceName, groupName, subscribe));}return instances;}@Overridepublic List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.getAllInstances(serviceName, clusters));}return instances;}@Overridepublic List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.getAllInstances(serviceName, groupName, clusters));}return instances;}@Overridepublic List<Instance> getAllInstances(String serviceName, List<String> clusters, boolean subscribe) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.getAllInstances(serviceName, clusters, subscribe));}return instances;}@Overridepublic List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters, boolean subscribe) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.getAllInstances(serviceName, groupName, clusters, subscribe));}return instances;}@Overridepublic List<Instance> selectInstances(String serviceName, boolean healthy) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.selectInstances(serviceName, healthy));}return instances;}@Overridepublic List<Instance> selectInstances(String serviceName, String groupName, boolean healthy) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.selectInstances(serviceName, groupName, healthy));}return instances;}@Overridepublic List<Instance> selectInstances(String serviceName, boolean healthy, boolean subscribe) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.selectInstances(serviceName, healthy, subscribe));}return instances;}@Overridepublic List<Instance> selectInstances(String serviceName, String groupName, boolean healthy, boolean subscribe) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.selectInstances(serviceName, groupName, healthy, subscribe));}return instances;}@Overridepublic List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.selectInstances(serviceName, clusters, healthy));}return instances;}@Overridepublic List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters, boolean healthy) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.selectInstances(serviceName, groupName, clusters, healthy));}return instances;}@Overridepublic List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy, boolean subscribe) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.selectInstances(serviceName, clusters, healthy, subscribe));}return instances;}@Overridepublic List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters, boolean healthy, boolean subscribe) throws NacosException {List<Instance> instances = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {instances.addAll(nacosNamingService.selectInstances(serviceName, groupName, clusters, healthy, subscribe));}return instances;}@Overridepublic Instance selectOneHealthyInstance(String serviceName) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {Instance instance = nacosNamingService.selectOneHealthyInstance(serviceName);if (instance != null) {return instance;}}return null;}@Overridepublic Instance selectOneHealthyInstance(String serviceName, String groupName) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {Instance instance = nacosNamingService.selectOneHealthyInstance(serviceName, groupName);if (instance != null) {return instance;}}return null;}@Overridepublic Instance selectOneHealthyInstance(String serviceName, boolean subscribe) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {Instance instance = nacosNamingService.selectOneHealthyInstance(serviceName, subscribe);if (instance != null) {return instance;}}return null;}@Overridepublic Instance selectOneHealthyInstance(String serviceName, String groupName, boolean subscribe) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {Instance instance = nacosNamingService.selectOneHealthyInstance(serviceName, groupName, subscribe);if (instance != null) {return instance;}}return null;}@Overridepublic Instance selectOneHealthyInstance(String serviceName, List<String> clusters) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {Instance instance = nacosNamingService.selectOneHealthyInstance(serviceName, clusters);if (instance != null) {return instance;}}return null;}@Overridepublic Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {Instance instance = nacosNamingService.selectOneHealthyInstance(serviceName, groupName, clusters);if (instance != null) {return instance;}}return null;}@Overridepublic Instance selectOneHealthyInstance(String serviceName, List<String> clusters, boolean subscribe) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {Instance instance = nacosNamingService.selectOneHealthyInstance(serviceName, clusters, subscribe);if (instance != null) {return instance;}}return null;}@Overridepublic Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters, boolean subscribe) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {Instance instance = nacosNamingService.selectOneHealthyInstance(serviceName, groupName, clusters, subscribe);if (instance != null) {return instance;}}return null;}@Overridepublic void subscribe(String serviceName, EventListener listener) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.subscribe(serviceName, listener);}}@Overridepublic void subscribe(String serviceName, String groupName, EventListener listener) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.subscribe(serviceName, groupName, listener);}}@Overridepublic void subscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.subscribe(serviceName, clusters, listener);}}@Overridepublic void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.subscribe(serviceName, groupName, clusters, listener);}}@Overridepublic void unsubscribe(String serviceName, EventListener listener) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.unsubscribe(serviceName, listener);}}@Overridepublic void unsubscribe(String serviceName, String groupName, EventListener listener) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.unsubscribe(serviceName, groupName, listener);}}@Overridepublic void unsubscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.unsubscribe(serviceName, clusters, listener);}}@Overridepublic void unsubscribe(String serviceName, String groupName, List<String> clusters, EventListener listener) throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.unsubscribe(serviceName, groupName, clusters, listener);}}@Overridepublic ListView<String> getServicesOfServer(int pageNo, int pageSize) throws NacosException {ListView<String> listView = new ListView<>();List<String> data = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {data.addAll(nacosNamingService.getServicesOfServer(pageNo, pageSize).getData());}listView.setData(data);return listView;}@Overridepublic ListView<String> getServicesOfServer(int pageNo, int pageSize, String groupName) throws NacosException {ListView<String> listView = new ListView<>();List<String> data = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {data.addAll(nacosNamingService.getServicesOfServer(pageNo, pageSize, groupName).getData());}listView.setData(data);return listView;}@Overridepublic ListView<String> getServicesOfServer(int pageNo, int pageSize, AbstractSelector selector) throws NacosException {ListView<String> listView = new ListView<>();List<String> data = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {data.addAll(nacosNamingService.getServicesOfServer(pageNo, pageSize, selector).getData());}listView.setData(data);return listView;}@Overridepublic ListView<String> getServicesOfServer(int pageNo, int pageSize, String groupName, AbstractSelector selector) throws NacosException {ListView<String> listView = new ListView<>();List<String> data = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {data.addAll(nacosNamingService.getServicesOfServer(pageNo, pageSize, groupName, selector).getData());}listView.setData(data);return listView;}@Overridepublic List<ServiceInfo> getSubscribeServices() {List<ServiceInfo> data = new ArrayList<>();for (NacosNamingService nacosNamingService : nacosNamingServices) {data.addAll(nacosNamingService.getSubscribeServices());}return data;}@Overridepublic String getServerStatus() {for (NacosNamingService nacosNamingService : nacosNamingServices) {String serverStatus = nacosNamingService.getServerStatus();if (STATUS_DOWN.equals(serverStatus)) {return STATUS_DOWN;}}return STATUS_UP;}@Overridepublic void shutDown() throws NacosException {for (NacosNamingService nacosNamingService : nacosNamingServices) {nacosNamingService.shutDown();}}
}

MultiNacosServiceAutoConfiguration
将MultiNacosServiceManager 设置为自动加载Bean,激活为主要的Bean。

import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosServiceManager;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class MultiNacosServiceAutoConfiguration {@Bean@Primarypublic NacosServiceManager multiNacosServiceManager() {return new MultiNacosServiceManager();}
}

总结

最终你能发现admin监控会同时注册到多个集群中,admin服务列表能看到多个集群的服务。另外要注意的是,要适当调整admin监控服务的内存,毕竟监控的服务变多了。
通过一个月的运行,目前admin监控运行稳定,相关功能一切正常。


其他企业级监控:
Prometheus 系列文章

  1. Prometheus 的介绍和安装
  2. 直观感受PromQL及其数据类型
  3. PromQL之选择器和运算符
  4. PromQL之函数
  5. Prometheus 告警机制介绍及命令解读
  6. Prometheus 告警模块配置深度解析
  7. Prometheus 配置身份认证
  8. Prometheus 动态拉取监控服务
  9. Prometheus 监控云Mysql和自建Mysql

Grafana 系列文章,版本:OOS v9.3.1

  1. Grafana 的介绍和安装
  2. Grafana监控大屏配置参数介绍(一)
  3. Grafana监控大屏配置参数介绍(二)
  4. Grafana监控大屏可视化图表
  5. Grafana 查询数据和转换数据
  6. Grafana 告警模块介绍
  7. Grafana 告警接入飞书通知

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

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

相关文章

S32 Design Studio的PE工具

S32 Design Studio软件是NXP公司专门为了方便用户开发S32K1系列芯片的IDE&#xff0c;跟Eclipse比较像。里面有个配套的图形工具Processor Expert&#xff0c;会产生一个后缀名为pe的文件&#xff0c;跟ST的cubemx作用类似。 双击pe文件即可打开pe界面&#xff0c;生成的文件将…

力扣hot100 -- 双指针

目录 &#x1f382;移动零 &#x1f319;盛最多水的容器 &#x1f33c;三数之和 &#x1f33c;接雨水 前缀和 辅助数组 双指针 单调栈 &#x1f382;移动零 283. 移动零 - 力扣&#xff08;LeetCode&#xff09; 关于swap #include <iostream> #include <vec…

vim 启用鼠标复制粘贴

其实这个是错误的标题&#xff0c; 其实是nvim&#xff0c;最近在使用parrot的vim时&#xff0c;发现右键粘贴文本的时候&#xff0c;左下显示-- &#xff08;insert&#xff09;VISUAL --&#xff0c;并且无法粘贴内容 一般网上会教你用set mouse-a &#xff0c;当然这个没有问…

Leetcode 3035. Maximum Palindromes After Operations

Leetcode 3035. Maximum Palindromes After Operations 1. 解题思路2. 代码实现 题目链接&#xff1a;3035. Maximum Palindromes After Operations 1. 解题思路 这一题的话因为可以任意交换&#xff0c;因此事实上要考察回文的最大个数&#xff0c;我们只需要统计所有单词当…

每日五道java面试题之java基础篇(五)

第一题. final、finally、finalize 的区别&#xff1f; final ⽤于修饰变量、⽅法和类&#xff1a;final 修饰的类不可被继承&#xff1b;修饰的⽅法不可被重写&#xff1b;修饰的变量不可变。finally 作为异常处理的⼀部分&#xff0c;它只能在 try/catch 语句中&#xff0c;…

JavaScript DOM 变动观察器(Mutation observer)

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ✨ 前言 DOM 变动观察 是 web 开发中的一个重要概念&#xff0c;指的是监视 …

《21天精通IPv4 to IPv6》第9天:云和容器中的IPv6——如何在云端☁️容器中实现IPv4到IPv6?

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

Lua Table库

table 库由一些操作 table 的辅助函数组成。他的主要作用之一是对 Lua 中 array 的大小给出一个合理的解释。另外还提供了一些从 list 中插入删除元素的函数&#xff0c;以及对 array 元素排序函数。 数组大小# 在programming in lua中教我们使用getn/setn来实现对array大小的…

无代码开发API集成:京推推助力电商平台和客服系统连接

一、无代码开发API的连接革命 无缝连接电商平台和客服系统在当前电子商务的快速发展下成为了企业面临的重要挑战。京推推推出了一种无代码开发API的解决方案&#xff0c;帮助商家无需进行复杂的API开发&#xff0c;即可将他们的在线商店与客户服务系统集成。这种方式使得商家…

Netty应用(七) 之 Handler Netty服务端编程总结

目录 15.Handler 15.1 handler的分类 15.1.1 按照方向划分 15.1.2 handler的结构 15.2 输入方向ChannelInboundHandlerAdapter 15.2.1 输出方向Handler的顺序 15.2.2 多个输入方向Handler之间的数据传递 15.2.2.1 handler消失了 15.2.2.2 手动编写netty提供的new Strin…

【C++】容器适配器结构的设计

目录 介绍&#xff1a; 一&#xff0c;queue结构的设计 二&#xff0c;priority_queue结构设计 三&#xff0c;stack结构设计 介绍&#xff1a; 适配器 适配器是一种设计模式&#xff0c;而设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计的总结&…

Javascript(二)注释和结束符

注释很详细&#xff0c;直接上代码 新增内容&#xff1a; 1.单行注释与多行注释&#xff08;内部及外部适用&#xff09; 2.结束符 外部注释 test.js //单行注释&#xff0c;快捷键Ctrlc(取消注释和注释相同)/* 多行注释,快捷键ShiftAltA(取消注释和注释相同) */// ; 为结束符…

django中的缓存功能

一&#xff1a;介绍 Django中的缓存功能是一个重要的性能优化手段&#xff0c;它可以将某些耗时的操作&#xff08;如数据库查询、复杂的计算等&#xff09;的结果存储起来&#xff0c;以便在后续的请求中直接使用这些缓存的结果&#xff0c;而不是重新执行耗时的操作。Django…

【机器学习】全网最全模型评价指标(性能指标、YOLOv5训练结果分析、轻量化指标、混淆矩阵详解)【基础收藏】

&#x1f951; Welcome to Aedream同学 s blog! &#x1f951; 文章目录 模型性能指标常见指标ROC/AUCROC & PRC多分类问题——混淆矩阵 计算结果分析——以YOLO v5为例1. confusion_matrix.png(混淆矩阵)2. F1_curve&#xff1a;3. labels.jpg4. labels_corrrelogram.jpg5…

免费分享一套PyQt6学生信息管理系统 Python管理系统 Python源码,挺漂亮的

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的PyQt6学生信息管理系统 Python管理系统 Python源码&#xff0c;分享下哈。 项目视频演示 【免费】PyQt5 学生信息管理系统 Python管理系统 Python源码 Python毕业设计_哔哩哔哩_bilibili【免费】PyQt5 学生…

揭秘:15条黄金法则,让你的GPT聊天提示效率翻倍!(一)

你的 ChatGPT 响应的好坏完全取决于你使用的ChatGPT 提示。 事实是&#xff0c;ChatgPT对于潜在客户开发、内容创建甚至外展都非常有效。 但大多数人只是使用人工智能来创建内容。 当然&#xff0c;它有时可以产生一些纯文本。也就是说&#xff0c;如果你只使用正确的提示。…

python 与 优先队列

文章目录 在 Python 中&#xff0c;可以使用 heapq 模块来实现优先队列。heapq 提供了一种基于堆的优先队列实现&#xff0c;堆是一种特殊的二叉树&#xff0c;满足父节点的值总是小于或等于其子节点的值&#xff08;最小堆&#xff09;或大于或等于其子节点的值&#xff08;最…

Junit常用注解

注解是方法的“标签” 说明每个方法的“职责” Q:总共有那些注解? 参见官方的API文档 0.常用主机及其特点 BeforeClass 只会执行一次必须用static修饰常用来初始化测试需要的变量 Before 会执行多次&#xff08;只要写一次&#xff09;在每个Test执行执行之前执行可以和…

fast.ai 机器学习笔记(一)

机器学习 1&#xff1a;第 1 课 原文&#xff1a;medium.com/hiromi_suenaga/machine-learning-1-lesson-1-84a1dc2b5236 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 来自机器学习课程的个人笔记。随着我继续复习课程以“真正”理解它&#xff0c;这些笔记将继续更…

rtt设备io框架面向对象学习-spi总线和设备

1.spi总线 spi总线分为硬件spi总线和软件模拟spi总线。 按照面向对象的思想&#xff0c;要抽象出硬件spi总线和软件spi总线的相同点和不同点。相同点就变成了spi总线基类&#xff0c;不同点就是各个子类的私有特性。 rtt就是这么干的&#xff0c;共同点是什么&#xff1f;方法…