KCloud-Platform-IoT KCloud-Platform-IoT
首页
  • 开发手册

    • 组件【ai】
    • 组件【algorithm】
    • 组件【banner】
    • 组件【clickhouse】
    • 组件【core】
    • 组件【bom】
    • 组件【cors】
    • 组件【domain】
    • 组件【crypto】
    • 组件【data-cache】
    • 组件【dubbo】
    • 组件【elasticsearch】
    • 组件【excel】
    • 组件【extension】
    • 组件【flink】
    • 组件【grpc】
    • 组件【i18n】
    • 组件【idempotent】
    • 组件【influxdb】
    • 组件【kafka】
    • 组件【log】
    • 组件【lock】
    • 组件【mail】
    • 组件【log4j2】
    • 组件【mqtt】
    • 组件【mongodb】
    • 组件【mybatis-plus】
    • 组件【nacos】
    • 组件【netty】
    • 组件【openapi-doc】
    • 组件【openfeign】
    • 组件【oss】
    • 组件【prometheus】
    • 组件【rabbitmq】
    • 组件【rate-limiter】
    • 组件【reactor】
    • 组件【redis】
    • 组件【rocketmq】
    • 组件【ruleengine】
    • 组件【secret】
    • 组件【security】
    • 组件【sensitive】
    • 组件【sentinel】
    • 组件【sms】
    • 组件【snail-job】
    • 组件【spark】
    • 组件【starrocks】
    • 组件【statemachine】
    • 组件【storage】
    • 组件【tdengine】
    • 组件【tenant】
    • 组件【test】
    • 组件【trace】
    • 组件【xss】
    • 组件【shardingsphere】
  • 环境搭建

    • Centos7安装Mysql 8.0.33
    • Centos7安装Redis 7.0.11
    • Centos7安装RocketMQ 5.1.1
    • Centos7安装Jdk 17.0.7
    • Centos7安装Docker 23.0.6
    • Centos7安装Elasticsearch 8.6.2
    • Docker安装RabbitMQ 3.12.2
    • Docker安装Postgresql 16.1
    • Ubuntu20.04安装Docker
    • Ubuntu20.04忘记密码或指纹错误
  • 常用命令

    • Centos7常用命令
    • Centos7常用命令
  • 快速上手

    • 项目启动【dev环境】
    • 项目启动【test环境】
    • 项目启动【prod环境】
    • 更新日志
  • 前端指南

    • 前端启动
  • 后端指南

    • COLA代码规范
    • SSL证书
    • 一键修改项目模块
    • 一键生成项目骨架
    • 一键修改项目版本号
    • 一键跳过测试用例
    • 一键生成后端COLA代码
    • 分布式链路跟踪之ELK日志
    • 一键检查代码规范
    • 动态路由
  • 项目部署

    • 项目部署之镜像打包与推送
  • 其他

    • Java如何快速转Go
    • Go快速开发API
    • Vue快速开发Api
    • React快速开发Api
  • 文章

    • 物联网之对接MQTT最佳实践
    • 物联网之使用Vertx实现MQTT-Server最佳实践【响应式】
    • vue3+lime-echart各种图表使用【懒人专用,建议收藏】
    • 物联网之使用Vertx实现TCP最佳实践【响应式】
    • 物联网之使用Vertx实现HTTPWebSocket最佳实践【响应式】
    • 物联网之使用Vertx实现UDP最佳实践【响应式】
  • 儒学

    • 儒学摘抄(一)
  • 禅语

    • 禅语摘抄(一)
  • 诗词

    • 诗词摘抄(一)
  • 道法

    • 道法摘抄(一)
  • 养生

    • 养生摘抄(一)
  • 读后感

    • 读《强者,都是含泪奔跑的人》读后感
  • 修行

    • 修身/养生/情感
  • 觉悟

    • 觉悟日记(一)
赞助
项目课程 (opens new window)
GitHub (opens new window)
首页
  • 开发手册

    • 组件【ai】
    • 组件【algorithm】
    • 组件【banner】
    • 组件【clickhouse】
    • 组件【core】
    • 组件【bom】
    • 组件【cors】
    • 组件【domain】
    • 组件【crypto】
    • 组件【data-cache】
    • 组件【dubbo】
    • 组件【elasticsearch】
    • 组件【excel】
    • 组件【extension】
    • 组件【flink】
    • 组件【grpc】
    • 组件【i18n】
    • 组件【idempotent】
    • 组件【influxdb】
    • 组件【kafka】
    • 组件【log】
    • 组件【lock】
    • 组件【mail】
    • 组件【log4j2】
    • 组件【mqtt】
    • 组件【mongodb】
    • 组件【mybatis-plus】
    • 组件【nacos】
    • 组件【netty】
    • 组件【openapi-doc】
    • 组件【openfeign】
    • 组件【oss】
    • 组件【prometheus】
    • 组件【rabbitmq】
    • 组件【rate-limiter】
    • 组件【reactor】
    • 组件【redis】
    • 组件【rocketmq】
    • 组件【ruleengine】
    • 组件【secret】
    • 组件【security】
    • 组件【sensitive】
    • 组件【sentinel】
    • 组件【sms】
    • 组件【snail-job】
    • 组件【spark】
    • 组件【starrocks】
    • 组件【statemachine】
    • 组件【storage】
    • 组件【tdengine】
    • 组件【tenant】
    • 组件【test】
    • 组件【trace】
    • 组件【xss】
    • 组件【shardingsphere】
  • 环境搭建

    • Centos7安装Mysql 8.0.33
    • Centos7安装Redis 7.0.11
    • Centos7安装RocketMQ 5.1.1
    • Centos7安装Jdk 17.0.7
    • Centos7安装Docker 23.0.6
    • Centos7安装Elasticsearch 8.6.2
    • Docker安装RabbitMQ 3.12.2
    • Docker安装Postgresql 16.1
    • Ubuntu20.04安装Docker
    • Ubuntu20.04忘记密码或指纹错误
  • 常用命令

    • Centos7常用命令
    • Centos7常用命令
  • 快速上手

    • 项目启动【dev环境】
    • 项目启动【test环境】
    • 项目启动【prod环境】
    • 更新日志
  • 前端指南

    • 前端启动
  • 后端指南

    • COLA代码规范
    • SSL证书
    • 一键修改项目模块
    • 一键生成项目骨架
    • 一键修改项目版本号
    • 一键跳过测试用例
    • 一键生成后端COLA代码
    • 分布式链路跟踪之ELK日志
    • 一键检查代码规范
    • 动态路由
  • 项目部署

    • 项目部署之镜像打包与推送
  • 其他

    • Java如何快速转Go
    • Go快速开发API
    • Vue快速开发Api
    • React快速开发Api
  • 文章

    • 物联网之对接MQTT最佳实践
    • 物联网之使用Vertx实现MQTT-Server最佳实践【响应式】
    • vue3+lime-echart各种图表使用【懒人专用,建议收藏】
    • 物联网之使用Vertx实现TCP最佳实践【响应式】
    • 物联网之使用Vertx实现HTTPWebSocket最佳实践【响应式】
    • 物联网之使用Vertx实现UDP最佳实践【响应式】
  • 儒学

    • 儒学摘抄(一)
  • 禅语

    • 禅语摘抄(一)
  • 诗词

    • 诗词摘抄(一)
  • 道法

    • 道法摘抄(一)
  • 养生

    • 养生摘抄(一)
  • 读后感

    • 读《强者,都是含泪奔跑的人》读后感
  • 修行

    • 修身/养生/情感
  • 觉悟

    • 觉悟日记(一)
赞助
项目课程 (opens new window)
GitHub (opens new window)
  • 开发手册

    • 组件【ai】
    • 组件【algorithm】
    • 组件【banner】
    • 组件【clickhouse】
    • 组件【core】
    • 组件【bom】
    • 组件【cors】
    • 组件【domain】
    • 组件【crypto】
    • 组件【data-cache】
    • 组件【dubbo】
    • 组件【elasticsearch】
    • 组件【excel】
    • 组件【extension】
    • 组件【flink】
    • 组件【grpc】
    • 组件【i18n】
    • 组件【idempotent】
    • 组件【influxdb】
    • 组件【kafka】
    • 组件【log】
    • 组件【lock】
    • 组件【mail】
    • 组件【log4j2】
    • 组件【mqtt】
    • 组件【mongodb】
    • 组件【mybatis-plus】
    • 组件【nacos】
      • 组件【netty】
      • 组件【openapi-doc】
      • 组件【openfeign】
      • 组件【oss】
      • 组件【prometheus】
      • 组件【rabbitmq】
      • 组件【rate-limiter】
      • 组件【reactor】
      • 组件【redis】
      • 组件【rocketmq】
      • 组件【ruleengine】
      • 组件【secret】
      • 组件【security】
      • 组件【sensitive】
      • 组件【sentinel】
      • 组件【sms】
      • 组件【snail-job】
      • 组件【spark】
      • 组件【starrocks】
      • 组件【statemachine】
      • 组件【storage】
      • 组件【tdengine】
      • 组件【tenant】
      • 组件【test】
      • 组件【trace】
      • 组件【xss】
      • 组件【shardingsphere】
    • 环境搭建

      • Centos7安装Mysql 8.0.33
      • Centos7安装Redis 7.0.11
      • Centos7安装RocketMQ 5.1.1
      • Centos7安装Jdk 17.0.7
      • Centos7安装Docker 23.0.6
      • Docker安装RabbitMQ 3.12.2
      • Centos7安装Elasticsearch 8.6.2
      • Docker安装Postgresql 16.1
      • Ubuntu20.04安装Docker
      • Ubuntu20.04忘记密码或指纹错误
    • 常用命令

      • Centos7常用命令
      • Docker常用命令
    • 快速上手

      • 项目启动【dev环境】
      • 项目启动【test环境】
      • 项目启动【prod环境】
      • 更新日志
    • 前端指南

      • 前端启动
    • 后端指南

      • COLA代码规范
      • SSL证书
      • 一键修改项目模块
      • 一键生成项目骨架
      • 一键修改项目版本号
      • 一键跳过测试用例
      • 一键生成后端COLA代码
      • 分布式链路跟踪之ELK日志
      • 一键检查代码规范
      • 动态路由
      • OAuth2.1流程
    • 项目部署

      • 项目部署之镜像打包与推送
    • 其他

      • Java如何快速转Go
      • Go快速开发API
      • Vue快速开发Api
      • React快速开发Api
    • 文章

      • 物联网之对接MQTT最佳实践
      • 物联网之使用Vertx实现MQTT-Server最佳实践【响应式】
      • vue3+lime-echart各种图表使用【懒人专用,建议收藏】
      • 物联网之使用Vertx实现TCP最佳实践【响应式】
      • 物联网之使用Vertx实现HTTPWebSocket最佳实践【响应式】
      • 物联网之使用Vertx实现UDP最佳实践【响应式】
    • 指南
    • 开发手册
    KCloud-Platform-IoT
    2025-03-11
    目录

    组件【nacos】

    小伙伴们,你们好,欢迎来到老寇云平台,这个组件【nacos】是配置中心&服务注册&发现

    nacos官方地址【最新版】 (opens new window)

    # Nacos介绍【摘抄自官方文档】

    Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、 配置管理和服务管理平台。

    Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

    Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以**“服务”**为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。

    # Nacos架构

    阅读架构图,我们可以得到以下结论

    • Nacos客户端配置了多级缓存【内存+文件】,即使Nacos集群不可用,仍然可以读取本地缓存
    • Nacos客户端与服务端通信采用gRPC,实现数据的高效传输,减少网络延迟
    • Nacos服务端将数据持久化到数据库或磁盘,确保数据不丢失
    • Nacos客户端发送心跳检测,超过时间标记为不健康服务,Nacos服务端通过心跳检测,将故障节点从路由表剔除
    • Nacos使用Raft协议管理集群元数据和配置数据,确保数据强一致性【数据写入多数节点(N/2+1)确认,避免出现脑裂问题】
    • Nacos服务注册数据默认存在内存中,通过Distro协议【AP模式】实现最终一致性

    总之,Nacos可以通过增加节点来水平扩展,提升系统的整体性能和承载能力

    # 项目部署

    jasypt:
    	encryptor:
    		# 加密算法
    		# springboot2加密密钥 => 使用MD5AndDES
    		algorithm: PBEWithMD5AndDES
    		# IV生成类
    		iv-generator-classname: org.jasypt.iv.NoIvGenerator
    		# 密钥
    		password: laokou
    
    db:
    	# 数据库数量,请按照作者的来,请不要瞎几把改
    	# 数据库数量,请按照作者的来,请不要瞎几把改
    	# 数据库数量,请按照作者的来,请不要瞎几把改
    	num: 1
    	# 数据库连接地址
    	url.'0': jdbc:postgresql://postgresql:5432/kcloud_platform?tcpKeepAlive=true&reWriteBatchedInserts=true&ApplicationName=laokou-nacos&useSSL=false&reWriteBatchedInserts=true&stringtype=unspecified
    	# 数据库用户名
    	user.'0': root
    	# 数据库密码
    	password.'0': laokou123
    	# see DataSourcePoolProperties 与 ExternalDataSourceProperties
    	pool:
    		config:
    			# see DataSourcePoolProperties
    			# see HikariConfig
    			# 最小空闲连接数
    			minimum-idle: 5
    			# 空闲连接的最大存活时间
    			idle-timeout: 600000
    			# 连接时间
    			connection-timeout: 30000
    			# 超时时间
    			validation-timeout: 10000
    			# 最大连接数
    			maximum-pool-size: 50
    			# 数据库驱动
    			driver-class-name: org.postgresql.Driver
    management:
    	metrics:
    		export:
    			elastic:
    				# 不暴露指标到Elastic
    				enabled: false
    			influx:
    				# 不暴露指标到Influx
    				enabled: false
    nacos:
    	config:
    		push:
    			# 配置推送失败时的最大重试次数
    			maxRetryTime: 50
    	core:
    		auth:
    			caching:
    				# 启用认证信息的缓存,减少重复认证的开销
    				enabled: true
    			enable:
    				# 禁止通过 User-Agent 请求头进行白名单认证 => 设置为 false 表示所有请求必须携带有效凭证(如 Token)
    				userAgentAuthWhite: false
    			enabled: true
    			plugin:
    				nacos:
    					token:
    						cache:
    							# 禁用 Token 缓存,每次请求需重新验证 Token
    							enable: false
    						expire:
    							#  Token 的有效期,超时后需重新获取
    							seconds: 18000
    						secret:
    							# 生成和验证 Token 的密钥
    							key: SecretKey012345678901234567890123456789012345678901234567890123456789
    			server:
    				identity:
    					# 服务节点间通信的认证标识,用于集群内部身份校验
    					key: serverIdentity
    					value: security
    			system:
    				# 指定系统类型为 Nacos
    				type: nacos
    	istio:
    		mcp:
    			server:
    				# 禁用 Istio 的 Mesh Configuration Protocol (MCP) 服务 =>  若不使用 Istio 服务网格,可关闭此功能
    				enabled: false
    	naming:
    		empty-service:
    			# 自动清理无实例注册的空服务
    			auto-clean: true
    			clean:
    				# 服务清理任务的初始延迟时间
    				initial-delay-ms: 50000
    				# 服务清理任务的执行间隔,每 30 秒检查一次
    				period-time-ms: 30000
    	security:
    		ignore:
    			# 配置无需认证即可访问的 URL 路径,通常用于静态资源或健康检查
    			urls: /,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
    server:
    	error:
    		# 应用程序在发生错误时,HTTP 响应中始终返回具体的错误消息
    		include-message: always
    	# 端口
    	port: ${SERVER_PORT:8848}
    	servlet:
    		# 请求上下文路径
    		contextPath: /nacos
    	undertow:
    		threads:
    			# 设置IO线程数,来执行非阻塞任务,负责多个连接数
    			io: 16
    			# 工作线程数
    			worker: 512
    		# 每块buffer的空间大小
    		buffer-size: 2048
    		# 分配堆外内存
    		direct-buffers: true
    		accesslog:
    			# 开启日志
    			enabled: true
    	ssl:
    		# 关闭证书
    		enabled: false
    	http2:
    		# 关闭http2
    		enabled: false
    	# 优雅停机
    	shutdown: graceful
    spring:
    	main:
    		# banner模式
    		banner-mode: console
    	application:
    		# 应用名称
    		name: laokou-nacos
    	profiles:
    		# 环境
    		active: test
    	sql:
    		init:
    			# 指定数据库类型
    			platform: postgresql
    	liquibase:
    		# 开启数据库版本管理工具
    		enabled: true
    		# 数据库版本变更配置
    		change-log: classpath:/db/changelog/db.changelog-master.xml
    		# 数据库用户名
    		user: root
    		# 数据库密码
    		password: laokou123
    		# 数据库连接地址
    		url: jdbc:postgresql://postgresql:5432/kcloud_platform_nacos?tcpKeepAlive=true&reWriteBatchedInserts=true&ApplicationName=laokou-nacos&useSSL=false&reWriteBatchedInserts=true&stringtype=unspecified
    

    # Java SDK使用

    ConfigUtil

    public final class ConfigUtil {
    
    	/**
    	 * 获取分组名称.
    	 */
    	public String getGroup();
    
    	/**
    	 * 创建配置服务.
    	 * @param serverAddr 服务地址
    	 */
    	public static ConfigService createConfigService(String serverAddr);
    
    	/**
    	 * 创建服务地址.
    	 * @param properties 配置
    	 */
    	public static ConfigService createConfigService(Properties properties);
    
    	// @formatter:off
    	/**
    	 * 获取配置.
    	 * @param dataId 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节
    	 * @param group 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过 128 字节
    	 * @param timeoutMs 读取配置超时时间,单位 ms,推荐值 3000
    	 * @return String
    	 */
    	public String getConfig(String dataId, String group, long timeoutMs);
    	// @formatter:on
    
    	// @formatter:off
    	/**
    	 * 获取配置.
    	 * @param dataId 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节
    	 * @param group 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过 128 字节
    	 * @param timeoutMs 读取配置超时时间,单位 ms,推荐值 3000
    	 * @param listener 监听器,配置变更进入监听器的回调函数
    	 * @return String
    	 */
    	public String getConfig(String dataId, String group, long timeoutMs, Listener listener);
    	// @formatter:on
    
    	// @formatter:off
    	/**
    	 * 增加监听配置.
    	 * @param dataId 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节
    	 * @param group 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过 128 字节
    	 * @param listener 监听器,配置变更进入监听器的回调函数
    	 */
    	public void addListener(String dataId, String group, Listener listener);
    	// @formatter:on
    
    	// @formatter:off
    	/**
    	 * 删除监听配置.
    	 * @param dataId 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节
    	 * @param group 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过 128 字节
    	 * @param listener 监听器,配置变更进入监听器的回调函数
    	 */
    	public void removeListener(String dataId, String group, Listener listener);
    	// @formatter:on
    
    	// @formatter:off
    	/**
    	 * 发布配置.
    	 * @param dataId 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节
    	 * @param group 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过 128 字节
    	 * @param content 配置内容
    	 */
    	public boolean publishConfig(String dataId, String group, String content);
    	// @formatter:on
    
    	// @formatter:off
    	/**
    	 * 发布配置.
    	 * @param dataId 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节
    	 * @param group 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过 128 字节
    	 * @param content 配置内容
    	 * @param type 配置类型【properties/xml/json/text/html/yaml/toml/unset】,默认为text
    	 */
    	public boolean publishConfig(String dataId, String group, String content, String type);
    	// @formatter:on
    
    	// @formatter:off
    	/**
    	 * 发布配置【CAS】.
    	 * @param dataId 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节
    	 * @param group 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过 128 字节
    	 * @param content 配置内容
    	 * @param casMd5 配置内容md5
    	 */
    	public boolean publishConfigCas(String dataId, String group, String content, String casMd5);
    	// @formatter:on
    
    	// @formatter:off
    	/**
    	 * 发布配置【CAS】.
    	 * @param dataId 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节
    	 * @param group 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过 128 字节
    	 * @param content 配置内容
    	 * @param casMd5 配置内容md5
    	 * @param type 配置类型【properties/xml/json/text/html/yaml/toml/unset】,默认为text
    	 */
    	public boolean publishConfigCas(String dataId, String group, String content, String casMd5, String type);
    	// @formatter:on
    
    	// @formatter:off
    	/**
    	 * 移除配置.
    	 * @param dataId 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节
    	 * @param group 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过 128 字节
    	 */
    	public boolean removeConfig(String dataId, String group);
    	// @formatter:on
    
    	// @formatter:off
    	/**
    	 * 获取服务状态.
    	 */
    	public String getServerStatus();
    	// @formatter:on
    
    	// @formatter:off
    	/**
    	 * 获取配置服务.
    	 */
    	private ConfigService getConfigService();
    	// @formatter:on
    
    }
    

    NamingUtil.util

    public final class NamingUtil {
    
    	/**
    	 * 创建服务发现.
    	 * @param serverAddr 服务地址
    	 */
    	public static NamingService createNamingService(String serverAddr);
    
    	/**
    	 * 创建服务发现.
    	 * @param properties 配置
    	 */
    	public static NamingService createNamingService(Properties properties);
    
    	/**
    	 * Nacos优雅停机.
    	 */
    	public void nacosServiceShutDown();
    
    	/**
    	 * 获取命名维护服务.
    	 * @param properties 配置
    	 */
    	public NamingMaintainService getNamingMaintainService(Properties properties);
    
    	/**
    	 * Nacos注册服务的信息是否变更.
    	 */
    	public boolean isNacosDiscoveryInfoChanged(NacosDiscoveryProperties currentNacosDiscoveryPropertiesCache);
    
    	/**
    	 * 通过服务ID获取服务实例.
    	 * @param serviceId 服务ID
    	 * @return 服务实例
    	 */
    	public List<Instance> getAllInstances(String serviceId);
    
    	/**
    	 * 通过服务ID和分组获取服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 */
    	public List<Instance> getAllInstances(String serviceId, String group);
    
    	/**
    	 * 通过服务ID和订阅标识获取所有服务实例.
    	 * @param serviceId 服务ID
    	 * @param subscribe 是否订阅
    	 */
    	public List<Instance> getAllInstances(String serviceId, boolean subscribe);
    
    	/**
    	 * 通过服务ID、分组和订阅标识获取所有服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param subscribe 是否订阅
    	 */
    	public List<Instance> getAllInstances(String serviceId, String group, boolean subscribe);
    
    	/**
    	 * 通过服务ID和集群列表获取所有服务实例.
    	 * @param serviceId 服务ID
    	 * @param clusters 集群列表
    	 */
    	public List<Instance> getAllInstances(String serviceId, List<String> clusters);
    
    	/**
    	 * 通过服务ID、分组和集群列表获取所有服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param clusters 集群列表
    	 */
    	public List<Instance> getAllInstances(String serviceId, String group, List<String> clusters);
    
    	/**
    	 * 通过服务ID、集群列表和订阅标识获取所有服务实例.
    	 * @param serviceId 服务ID
    	 * @param clusters 集群列表
    	 * @param subscribe 是否订阅
    	 */
    	public List<Instance> getAllInstances(String serviceId, List<String> clusters, boolean subscribe);
    
    	/**
    	 * 通过服务ID、分组、集群列表和订阅标识获取所有服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param clusters 集群列表
    	 * @param subscribe 是否订阅
    	 */
    	public List<Instance> getAllInstances(String serviceId, String group, List<String> clusters, boolean subscribe);
    
    	/**
    	 * 注册实例.
    	 * @param serviceId 服务ID
    	 * @param ip 服务IP
    	 * @param port 服务端口
    	 */
    	public void registerInstance(String serviceId, String ip, int port);
    
    	/**
    	 * 注册服务.
    	 * @param serviceId 服务ID
    	 * @param group 服务分组
    	 * @param ip 服务IP
    	 * @param port 服务端口
    	 */
    	public void registerInstance(String serviceId, String group, String ip, int port);
    
    	/**
    	 * 注册服务实例.
    	 * @param serviceId 服务ID
    	 * @param clusterName 集群名称
    	 * @param ip 服务IP
    	 * @param port 服务端口
    	 */
    	public void registerInstance(String serviceId, String ip, int port, String clusterName);
    
    	/**
    	 * 注册服务实例.
    	 * @param serviceId 服务ID
    	 * @param clusterName 集群名称
    	 * @param ip 服务IP
    	 * @param port 服务端口
    	 * @param group 服务分组
    	 */
    	public void registerInstance(String serviceId, String group, String ip, int port, String clusterName);
    
    	/**
    	 * 注册服务实例.
    	 * @param serviceId 服务ID
    	 * @param instance 服务实例
    	 */
    	public void registerInstance(String serviceId, Instance instance);
    
    	/**
    	 * 注册服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 服务分组
    	 * @param instance 服务实例
    	 */
    	public void registerInstance(String serviceId, String group, Instance instance);
    
    	/**
    	 * 注销服务实例.
    	 * @param serviceId 服务ID
    	 * @param ip 服务IP
    	 * @param port 服务端口
    	 */
    	public void deregisterInstance(String serviceId, String ip, int port);
    
    	/**
    	 * 注销服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 服务分组
    	 * @param ip 服务IP
    	 * @param port 服务端口
    	 */
    	public void deregisterInstance(String serviceId, String group, String ip, int port);
    
    	/**
    	 * 注销服务实例.
    	 * @param serviceId 服务ID
    	 * @param clusterName 集群名称
    	 * @param ip 服务IP
    	 * @param port 服务端口
    	 */
    	public void deregisterInstance(String serviceId, String ip, int port, String clusterName);
    
    	/**
    	 * 注销服务实例.
    	 * @param serviceId 服务ID
    	 * @param clusterName 集群名称
    	 * @param ip 服务IP
    	 * @param port 服务端口
    	 * @param group 服务分组
    	 */
    	public void deregisterInstance(String serviceId, String group, String ip, int port, String clusterName);
    
    	/**
    	 * 注销服务实例.
    	 * @param serviceId 服务ID
    	 * @param instance 服务实例
    	 */
    	public void deregisterInstance(String serviceId, Instance instance);
    
    	/**
    	 * 注销服务实例.
    	 * @param serviceId 服务ID
    	 * @param instance 服务实例
    	 * @param group 服务分组
    	 */
    	public void deregisterInstance(String serviceId, String group, Instance instance);
    
    	/**
    	 * 根据服务ID和健康标识查询服务实例.
    	 * @param serviceId 服务ID
    	 * @param healthy 是否健康
    	 */
    	public List<Instance> selectInstances(String serviceId, boolean healthy);
    
    	/**
    	 * 根据服务ID、分组和健康标识查询服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param healthy 是否健康
    	 */
    	public List<Instance> selectInstances(String serviceId, String group, boolean healthy);
    
    	/**
    	 * 根据服务ID和集群列表查询服务实例.
    	 * @param serviceId 服务ID
    	 * @param healthy 是否健康
    	 * @param subscribe 是否订阅
    	 */
    	public List<Instance> selectInstances(String serviceId, boolean healthy, boolean subscribe);
    
    	/**
    	 * 根据服务ID、分组和集群列表查询服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param healthy 是否健康
    	 * @param subscribe 是否订阅
    	 */
    	public List<Instance> selectInstances(String serviceId, String group, boolean healthy, boolean subscribe);
    
    	/**
    	 * 根据服务ID、集群列表和健康查询服务实例.
    	 * @param serviceId 服务ID
    	 * @param clusters 集群列表
    	 * @param healthy 是否健康
    	 */
    	public List<Instance> selectInstances(String serviceId, List<String> clusters, boolean healthy);
    
    	/**
    	 * 根据服务ID、分组、集群列表和健康查询服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param clusters 集群列表
    	 * @param healthy 是否健康
    	 */
    	public List<Instance> selectInstances(String serviceId, String group, List<String> clusters, boolean healthy);
    
    	/**
    	 * 根据服务ID、集群列表、健康和订阅查询服务实例.
    	 * @param serviceId 服务ID
    	 * @param clusters 集群列表
    	 * @param healthy 是否健康
    	 * @param subscribe 是否订阅
    	 */
    	public List<Instance> selectInstances(String serviceId, List<String> clusters, boolean healthy, boolean subscribe);
    
    	/**
    	 * 根据服务ID、分组、集群列表、健康和订阅查询服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param clusters 集群列表
    	 * @param healthy 是否健康
    	 * @param subscribe 是否订阅
    	 */
    	public List<Instance> selectInstances(String serviceId, String group, List<String> clusters, boolean healthy, boolean subscribe);
    
    	/**
    	 * 根据服务ID查询健康的服务实例.
    	 * @param serviceId 服务ID
    	 */
    	public Instance selectOneHealthyInstance(String serviceId);
    
    	/**
    	 * 根据服务ID和分组查询健康的服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 */
    	public Instance selectOneHealthyInstance(String serviceId, String group);
    
    	/**
    	 * 根据服务ID和订阅标识查询健康的服务实例.
    	 * @param serviceId 服务ID
    	 * @param subscribe 是否订阅
    	 */
    	public Instance selectOneHealthyInstance(String serviceId, boolean subscribe);
    
    	/**
    	 * 根据服务ID、分组和订阅标识查询一个健康的服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param subscribe 是否订阅
    	 */
    	public Instance selectOneHealthyInstance(String serviceId, String group, boolean subscribe);
    
    	/**
    	 * 根据服务ID和集群列表查询一个健康的服务实例.
    	 * @param serviceId 服务ID
    	 * @param clusters 集群列表
    	 */
    	public Instance selectOneHealthyInstance(String serviceId, List<String> clusters);
    
    	/**
    	 * 根据服务ID、分组和集群列表查询一个健康的服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param clusters 集群列表
    	 */
    	public Instance selectOneHealthyInstance(String serviceId, String group, List<String> clusters);
    
    	/**
    	 * 根据服务ID、集群列表和订阅查询一个健康的服务实例.
    	 * @param serviceId 服务ID
    	 * @param clusters 集群列表
    	 * @param subscribe 是否订阅
    	 */
    	public Instance selectOneHealthyInstance(String serviceId, List<String> clusters, boolean subscribe);
    
    	/**
    	 * 根据服务ID、分组、集群列表和订阅查询一个健康的服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param clusters 集群列表
    	 * @param subscribe 是否订阅
    	 */
    	public Instance selectOneHealthyInstance(String serviceId, String group, List<String> clusters, boolean subscribe);
    
    	/**
    	 * 根据服务ID订阅服务并监听.
    	 * @param serviceId 服务ID
    	 * @param listener 监听器
    	 */
    	public void subscribe(String serviceId, EventListener listener);
    
    	/**
    	 * 根据服务ID和分组订阅服务并监听.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param listener 监听器
    	 */
    	public void subscribe(String serviceId, String group, EventListener listener);
    
    	/**
    	 * 根据服务ID和集群列表订阅服务并监听.
    	 * @param serviceId 服务ID
    	 * @param clusters 集群列表
    	 * @param listener 监听器
    	 */
    	public void subscribe(String serviceId, List<String> clusters, EventListener listener);
    
    	/**
    	 * 根据服务ID、分组和集群列表订阅服务并监听.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param clusters 集群列表
    	 * @param listener 监听器
    	 */
    	public void subscribe(String serviceId, String group, List<String> clusters, EventListener listener);
    
    	/**
    	 * 根据服务ID取消订阅并监听.
    	 * @param serviceId 服务ID
    	 * @param listener 监听器
    	 */
    	public void unsubscribe(String serviceId, EventListener listener);
    
    	/**
    	 * 根据服务ID和分组取消订阅并监听.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param listener 监听器
    	 */
    	public void unsubscribe(String serviceId, String group, EventListener listener);
    
    	/**
    	 * 根据服务ID和集群列表取消订阅并监听.
    	 * @param serviceId 服务ID
    	 * @param clusters 集群列表
    	 * @param listener 监听器
    	 */
    	public void unsubscribe(String serviceId, List<String> clusters, EventListener listener);
    
    	/**
    	 * 根据服务ID、分组和集群列表取消订阅并监听.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param clusters 集群列表
    	 * @param listener 监听器
    	 */
    	public void unsubscribe(String serviceId, String group, List<String> clusters, EventListener listener);
    
    	/**
    	 * 根据服务ID、分组和服务实例列表批量注册服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param instances 服务实例列表
    	 */
    	public void batchRegisterInstance(String serviceId, String group, List<Instance> instances);
    
    	/**
    	 * 根据服务ID和服务实例列表批量取消注册服务实例.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param instances 服务实例列表
    	 */
    	public void batchDeregisterInstance(String serviceId, String group, List<Instance> instances);
    
    	/**
    	 * 根据服务ID和选择器订阅并监听事件.
    	 * @param serviceId 服务ID
    	 * @param selector 选择器
    	 * @param listener 事件监听器
    	 */
    	public void subscribe(String serviceId, NamingSelector selector, EventListener listener);
    
    	/**
    	 * 根据服务ID、分组和选择器订阅并监听事件.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param selector 选择器
    	 * @param listener 事件监听器
    	 */
    	public void subscribe(String serviceId, String group, NamingSelector selector, EventListener listener);
    
    	/**
    	 * 根据服务ID和选择器取消订阅并监听事件.
    	 * @param serviceId 服务ID
    	 * @param selector 选择器
    	 * @param listener 事件监听器
    	 */
    	public void unsubscribe(String serviceId, NamingSelector selector, EventListener listener);
    
    	/**
    	 * 根据服务ID、分组和选择器取消订阅并监听事件.
    	 * @param serviceId 服务ID
    	 * @param group 分组
    	 * @param selector 选择器
    	 * @param listener 事件监听器
    	 */
    	public void unsubscribe(String serviceId, String group, NamingSelector selector, EventListener listener);
    
    	/**
    	 * 分页获取服务列表.
    	 * @param pageNo 页数
    	 * @param pageSize 条数
    	 */
    	public ListView<String> getServicesOfServer(int pageNo, int pageSize);
    
    	/**
    	 * 根据分组分页获取服务列表.
    	 * @param pageNo 页数
    	 * @param pageSize 条数
    	 * @param group 分组
    	 */
    	public ListView<String> getServicesOfServer(int pageNo, int pageSize, String group);
    
    	/**
    	 * 获取订阅服务列表.
    	 */
    	public List<ServiceInfo> getSubscribeServices();
    
    	/**
    	 * 获取发现服务.
    	 */
    	private NamingService getNamingService();
    
    }
    

    测试用例 ConfigUtilsTest

    class ConfigUtilsTest {
    
    	// @formatter:off
    	private ConfigUtils configUtils;
    
    	private NacosConfigProperties nacosConfigProperties;
    
    	@BeforeEach
    	void setUp() {
    		nacosConfigProperties = new NacosConfigProperties();
    		nacosConfigProperties.setServerAddr("127.0.0.1:8848");
    		nacosConfigProperties.setNamespace("public");
    		nacosConfigProperties.setUsername("nacos");
    		nacosConfigProperties.setPassword("nacos");
    		nacosConfigProperties.setGroup("DEFAULT_GROUP");
    
    		Assertions.assertNotNull(nacosConfigProperties);
    		Assertions.assertEquals("public", nacosConfigProperties.getNamespace());
    		Assertions.assertEquals("127.0.0.1:8848", nacosConfigProperties.getServerAddr());
    		Assertions.assertEquals("nacos", nacosConfigProperties.getPassword());
    		Assertions.assertEquals("nacos", nacosConfigProperties.getUsername());
    		Assertions.assertEquals("DEFAULT_GROUP", nacosConfigProperties.getGroup());
    		Assertions.assertNotNull(nacosConfigProperties.assembleConfigServiceProperties());
    
    		NacosConfigManager nacosConfigManager = new NacosConfigManager(nacosConfigProperties);
    		Assertions.assertNotNull(nacosConfigManager);
    
    		configUtils = new ConfigUtils(nacosConfigManager);
    		Assertions.assertNotNull(configUtils);
    	}
    
    	@Test
    	void testGetGroup() {
    		Assertions.assertEquals("DEFAULT_GROUP", configUtils.getGroup());
    	}
    
    	@Test
    	void testCreateConfigService() throws NacosException {
    		ConfigService configService = ConfigUtils.createConfigService(nacosConfigProperties.getServerAddr());
    		Assertions.assertNotNull(configService);
    		Assertions.assertEquals("UP", configService.getServerStatus());
    
    		configService = ConfigUtils.createConfigService(nacosConfigProperties.assembleConfigServiceProperties());
    		Assertions.assertNotNull(configService);
    		Assertions.assertEquals("UP", configService.getServerStatus());
    	}
    
    	@Test
    	void testGetConfig() throws NacosException {
    		String config = configUtils.getConfig("test.yaml", nacosConfigProperties.getGroup(), 5000);
    		Assertions.assertNotNull(config);
    		Assertions.assertTrue(config.contains("test"));
    		config = configUtils.getConfig("test.yaml", nacosConfigProperties.getGroup(), 5000, new Listener() {
    			@Override
    			public Executor getExecutor() {
    				return Executors.newSingleThreadExecutor();
    			}
    
    			@Override
    			public void receiveConfigInfo(String s) {
    				Assertions.assertNotNull(s);
    				Assertions.assertTrue(s.contains("test"));
    			}
    		});
    		Assertions.assertNotNull(config);
    		Assertions.assertTrue(config.contains("test"));
    	}
    
    	@Test
    	void testAddListener() throws NacosException {
    		configUtils.addListener("test.yaml", nacosConfigProperties.getGroup(), new Listener() {
    			@Override
    			public Executor getExecutor() {
    				return Executors.newSingleThreadExecutor();
    			}
    
    			@Override
    			public void receiveConfigInfo(String s) {
    				Assertions.assertNotNull(s);
    				Assertions.assertTrue(s.contains("test"));
    			}
    		});
    	}
    
    	@Test
    	void testRemoveListener() throws NacosException {
    		configUtils.removeListener("test.yaml", nacosConfigProperties.getGroup(), new Listener() {
    			@Override
    			public Executor getExecutor() {
    				return Executors.newSingleThreadExecutor();
    			}
    
    			@Override
    			public void receiveConfigInfo(String s) {
    				Assertions.assertNotNull(s);
    				Assertions.assertTrue(s.contains("test"));
    			}
    		});
    	}
    
    	@Test
    	void testPublishConfig() throws NacosException, InterruptedException {
    		Assertions.assertTrue(configUtils.publishConfig("test.yaml", nacosConfigProperties.getGroup(), "test: 123"));
    		Thread.sleep(100);
    		Assertions.assertEquals("test: 123", configUtils.getConfig("test.yaml", nacosConfigProperties.getGroup(), 5000));
    
    		Assertions.assertTrue(configUtils.publishConfig("test.yaml", nacosConfigProperties.getGroup(), "test: 456", "yaml"));
    		Assertions.assertEquals("test: 456", configUtils.getConfig("test.yaml", nacosConfigProperties.getGroup(), 5000));
    
    		Assertions.assertTrue(configUtils.publishConfig("test.yaml", nacosConfigProperties.getGroup(), "test: 123"));
    		Assertions.assertEquals("test: 123", configUtils.getConfig("test.yaml", nacosConfigProperties.getGroup(), 5000));
    
    		String md5 = DigestUtils.md5DigestAsHex("test: 123".getBytes());
    		Assertions.assertEquals("5e76b5e94b54e1372f8b452ef64dc55c", md5);
    		Assertions.assertTrue(configUtils.publishConfigCas("test.yaml", nacosConfigProperties.getGroup(), "test: 456", md5));
    		Assertions.assertEquals("test: 456", configUtils.getConfig("test.yaml", nacosConfigProperties.getGroup(), 5000));
    
    		md5 = DigestUtils.md5DigestAsHex("test: 456".getBytes());
    		Assertions.assertEquals("76e2eabbf24a8c90dc3b4372c20a72cf", md5);
    		Assertions.assertTrue(configUtils.publishConfigCas("test.yaml", nacosConfigProperties.getGroup(), "test: 789", md5, "yaml"));
    		Assertions.assertEquals("test: 789", configUtils.getConfig("test.yaml", nacosConfigProperties.getGroup(), 5000));
    	}
    
    	@Test
    	void testRemoveConfig() throws NacosException, InterruptedException {
    		Assertions.assertTrue(configUtils.publishConfig("test1.yaml", nacosConfigProperties.getGroup(), "test: 123"));
    		Thread.sleep(2000);
    		Assertions.assertEquals("test: 123", configUtils.getConfig("test1.yaml", nacosConfigProperties.getGroup(), 5000));
    
    		Assertions.assertTrue(configUtils.removeConfig("test1.yaml", nacosConfigProperties.getGroup()));
    		Assertions.assertNull(configUtils.getConfig("test1.yaml", nacosConfigProperties.getGroup(), 5000));
    	}
    
    	@Test
    	void testGetServerStatus() {
    		Assertions.assertEquals("UP", configUtils.getServerStatus());
    	}
    	// @formatter:on
    
    }
    
    

    NamingUtilsTest

    @Slf4j
    @SpringBootTest
    @RequiredArgsConstructor
    @ContextConfiguration(classes = { NamingUtils.class,
    	NacosServiceManager.class,
    	NacosDiscoveryProperties.class,
    	ApplicationEventPublisher.class,
    	InetUtilsProperties.class,
    	Environment.class,
    	InetUtils.class,
    	InetIPv6Utils.class })
    @TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
    class NamingUtilsTest {
    
    	private final NamingUtils namingUtils;
    
    	private final NacosDiscoveryProperties nacosDiscoveryProperties;
    
    	@BeforeEach
    	void setUp() {
    		Assertions.assertNotNull(nacosDiscoveryProperties);
    		Assertions.assertEquals("public", nacosDiscoveryProperties.getNamespace());
    		Assertions.assertEquals("127.0.0.1:8848", nacosDiscoveryProperties.getServerAddr());
    		Assertions.assertEquals("DEFAULT_GROUP", nacosDiscoveryProperties.getGroup());
    		Assertions.assertEquals("nacos", nacosDiscoveryProperties.getUsername());
    		Assertions.assertEquals("nacos", nacosDiscoveryProperties.getPassword());
    		Assertions.assertEquals("", nacosDiscoveryProperties.getEndpoint());
    		Assertions.assertEquals("", nacosDiscoveryProperties.getAccessKey());
    		Assertions.assertEquals("", nacosDiscoveryProperties.getSecretKey());
    		Assertions.assertEquals("laokou-cluster", nacosDiscoveryProperties.getClusterName());
    		Assertions.assertNotNull(nacosDiscoveryProperties.getNacosProperties());
    		Assertions.assertNotNull(namingUtils);
    	}
    
    	@Test
    	void testCreateNamingService() throws Exception {
    		NamingService namingService = NamingUtils.createNamingService(nacosDiscoveryProperties.getServerAddr());
    		Assertions.assertNotNull(namingService);
    		namingService = NamingUtils.createNamingService(nacosDiscoveryProperties.getNacosProperties());
    		Assertions.assertNotNull(namingService);
    	}
    
    	@Test
    	void testGetNamingMaintainService() {
    		NamingMaintainService namingMaintainService = namingUtils.getNamingMaintainService(nacosDiscoveryProperties.getNacosProperties());
    		Assertions.assertNotNull(namingMaintainService);
    	}
    
    	@Test
    	void testIsNacosDiscoveryInfoChanged() {
    		Assertions.assertFalse(namingUtils.isNacosDiscoveryInfoChanged(nacosDiscoveryProperties));
    	}
    
    	@Test
    	void testGetAllInstances() throws NacosException, InterruptedException {
    		Assertions.assertTrue(namingUtils.getAllInstances("test-service").isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", "127.0.0.1", 8080));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.getAllInstances("test-service").isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", "127.0.0.1", 8080));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.getAllInstances("test-service", "DEFAULT_GROUP").isEmpty());
    
    		Instance instance = new Instance();
    		instance.setIp("127.0.0.1");
    		instance.setPort(8080);
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", instance));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.getAllInstances("test-service", "DEFAULT_GROUP", false).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", instance));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.getAllInstances("test-service", false).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", "DEFAULT_GROUP", instance));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.getAllInstances("test-service", Collections.emptyList()).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", "DEFAULT_GROUP", instance));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.getAllInstances("test-service", "DEFAULT_GROUP", Collections.emptyList()).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", "DEFAULT_GROUP", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.getAllInstances("test-service", List.of(nacosDiscoveryProperties.getClusterName()), false).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", "DEFAULT_GROUP", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.getAllInstances("test-service", "DEFAULT_GROUP", List.of(nacosDiscoveryProperties.getClusterName()), false).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", "DEFAULT_GROUP", "127.0.0.1", 8080));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.getAllInstances("test-service", "DEFAULT_GROUP", false).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", "DEFAULT_GROUP", "127.0.0.1", 8080));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.getAllInstances("test-service", "DEFAULT_GROUP", false).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.getAllInstances("test-service", "DEFAULT_GROUP", List.of(nacosDiscoveryProperties.getClusterName()), false).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.getAllInstances("test-service", "DEFAULT_GROUP", List.of(nacosDiscoveryProperties.getClusterName()), false).isEmpty());
    	}
    
    	@Test
    	void testSelectInstances() throws NacosException, InterruptedException {
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", true).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.selectInstances("test-service", true).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", true, false).isEmpty());
    
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", "DEFAULT_GROUP", true, false).isEmpty());
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", List.of(nacosDiscoveryProperties.getClusterName()), true).isEmpty());
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", "DEFAULT_GROUP", List.of(nacosDiscoveryProperties.getClusterName()), true, false).isEmpty());
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", List.of(nacosDiscoveryProperties.getClusterName()), true, false).isEmpty());
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", "DEFAULT_GROUP", true).isEmpty());
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", "DEFAULT_GROUP", List.of(nacosDiscoveryProperties.getClusterName()), true).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.getAllInstances("test-service", "DEFAULT_GROUP", List.of(nacosDiscoveryProperties.getClusterName()), false).isEmpty());
    	}
    
    	@Test
    	void testSelectOneHealthyInstance() throws NacosException, InterruptedException {
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", true).isEmpty());
    
    		Assertions.assertNotNull(namingUtils.selectOneHealthyInstance("test-service"));
    		Assertions.assertNotNull(namingUtils.selectOneHealthyInstance("test-service", "DEFAULT_GROUP"));
    		Assertions.assertNotNull(namingUtils.selectOneHealthyInstance("test-service", false));
    		Assertions.assertNotNull(namingUtils.selectOneHealthyInstance("test-service", "DEFAULT_GROUP", false));
    		Assertions.assertNotNull(namingUtils.selectOneHealthyInstance("test-service", List.of(nacosDiscoveryProperties.getClusterName())));
    		Assertions.assertNotNull(namingUtils.selectOneHealthyInstance("test-service", "DEFAULT_GROUP", List.of(nacosDiscoveryProperties.getClusterName())));
    		Assertions.assertNotNull(namingUtils.selectOneHealthyInstance("test-service", List.of(nacosDiscoveryProperties.getClusterName()), false));
    		Assertions.assertNotNull(namingUtils.selectOneHealthyInstance("test-service", "DEFAULT_GROUP", List.of(nacosDiscoveryProperties.getClusterName()), false));
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.selectInstances("test-service", true).isEmpty());
    	}
    
    	@Test
    	void testSubscribeService() throws NacosException, InterruptedException {
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", true).isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.subscribe("test-service", "DEFAULT_GROUP", Assertions::assertNotNull));
    		Assertions.assertDoesNotThrow(() -> namingUtils.unsubscribe("test-service", "DEFAULT_GROUP", Assertions::assertNotNull));
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.subscribe("test-service", Assertions::assertNotNull));
    		Assertions.assertDoesNotThrow(() -> namingUtils.unsubscribe("test-service", Assertions::assertNotNull));
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.subscribe("test-service", "DEFAULT_GROUP", List.of(nacosDiscoveryProperties.getClusterName()), Assertions::assertNotNull));
    		Assertions.assertDoesNotThrow(() -> namingUtils.unsubscribe("test-service", "DEFAULT_GROUP", List.of(nacosDiscoveryProperties.getClusterName()), Assertions::assertNotNull));
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.subscribe("test-service", List.of(nacosDiscoveryProperties.getClusterName()), Assertions::assertNotNull));
    		Assertions.assertDoesNotThrow(() -> namingUtils.unsubscribe("test-service", List.of(nacosDiscoveryProperties.getClusterName()), Assertions::assertNotNull));
    
    		// 只选择订阅ip为`127.0`开头的实例。
    		NamingSelector selector = NamingSelectorFactory.newIpSelector("127.0.*");
    		Assertions.assertDoesNotThrow(() -> namingUtils.subscribe("test-service", "DEFAULT_GROUP", selector, Assertions::assertNotNull));
    		Assertions.assertDoesNotThrow(() -> namingUtils.unsubscribe("test-service", "DEFAULT_GROUP", selector, Assertions::assertNotNull));
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.subscribe("test-service", selector, Assertions::assertNotNull));
    		Assertions.assertDoesNotThrow(() -> namingUtils.unsubscribe("test-service", selector, Assertions::assertNotNull));
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.selectInstances("test-service", true).isEmpty());
    	}
    
    	@Test
    	void testGetServicesOfServer() throws NacosException, InterruptedException {
    		Assertions.assertDoesNotThrow(() -> namingUtils.registerInstance("test-service", "DEFAULT_GROUP", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertFalse(namingUtils.selectInstances("test-service", true).isEmpty());
    
    		Assertions.assertTrue(namingUtils.getServicesOfServer(1, 10, "DEFAULT_GROUP").getCount() > 0);
    		Assertions.assertTrue(namingUtils.getServicesOfServer(1, 10).getCount() > 0);
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.subscribe("test-service", "DEFAULT_GROUP", Assertions::assertNotNull));
    		Assertions.assertFalse(namingUtils.getSubscribeServices().isEmpty());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.deregisterInstance("test-service", "DEFAULT_GROUP", "127.0.0.1", 8080, nacosDiscoveryProperties.getClusterName()));
    		Thread.sleep(1000);
    		Assertions.assertTrue(namingUtils.selectInstances("test-service", true).isEmpty());
    	}
    
    	@Test
    	void testBatchRegisterInstance() throws NacosException, InterruptedException {
    		Instance instance = new Instance();
    		instance.setIp("127.0.0.1");
    		instance.setPort(8080);
    		Assertions.assertDoesNotThrow(() -> namingUtils.batchRegisterInstance("test-service", "DEFAULT_GROUP", List.of(instance)));
    		Thread.sleep(1000);
    		Assertions.assertNotEquals(2, namingUtils.selectInstances("test-service", true).size());
    
    		Assertions.assertDoesNotThrow(() -> namingUtils.batchDeregisterInstance("test-service", "DEFAULT_GROUP", List.of(instance)));
    		Thread.sleep(1000);
    		Assertions.assertEquals(0, namingUtils.selectInstances("test-service", false).size());
    	}
    
    	@Test
    	void testNacosServiceShutDown() throws InterruptedException {
    		Thread.sleep(1000);
    		Assertions.assertDoesNotThrow(namingUtils::nacosServiceShutDown);
    	}
    
    }
    // @formatter:on
    
    spring:
      config:
        import:
    	  # 导入配置文件
          - optional:nacos:application-common.yaml?refreshEnabled=true&group=DEFAULT_GROUP
      cloud:
        nacos:
          discovery:
    		# 服务发现地址
            server-addr: nacos:8848
    		# 命名空间
    		namespace: public
    		# 用户名
    		username: nacos
            # 密码
    		password: nacos
    		# 分组名称
            group: DEFAULT_GROUP
            # https
            secure: true
            # true 临时 false 持久
            ephemeral: true
            # 集群名称
            cluster-name: laokou-cluster
    		heart-beat:
    			# 开启心跳
    			enabled: true
    		# 每10秒发送一次心跳【单位毫秒】
    		heart-beat-interval: 10000
    		# 超过30秒,则标记为不健康
    		heart-beat-timeout: 30000
          config:
    		# 服务配置的地址
            server-addr: nacos:8848
    		# 命名空间
            namespace: public
    		# 用户名
            username: nacos
    		# 密码
            password: nacos
    		# 集群名称
            cluster-name: laokou-cluster
            # https://github.com/alibaba/spring-cloud-alibaba/blob/2021.x/spring-cloud-alibaba-docs/src/main/asciidoc-zh/nacos-config.adoc
            # 指定读取的文件格式
            file-extension: yaml
    		# 分组名称
            group: DEFAULT_GROUP
    		# 开启刷新
            refresh-enabled: true
    

    我是老寇,我们下次再见啦!

    上次更新: 5/21/2025, 5:17:33 PM
    组件【mybatis-plus】
    组件【netty】

    ← 组件【mybatis-plus】 组件【netty】→

    Theme by Vdoing | Copyright © 2022-2025 laokou | Apache 2.0 License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式