组件【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: 5201314wumeihua
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
我是老寇,我们下次再见
上次更新: 4/2/2025, 4:31:30 AM