Java SDK 使用手册
Nacos 的 Java SDK(或称Nacos-Java-Client),是一个针对 Nacos 配置中心、服务注册中心、分布式锁等场景的 Java SDK。旨在为Java的微服务或分布式应用提供稳定易用的配置中心、服务注册中心、分布式锁等功能,方便开发者访问Nacos进行配置、服务和分布式锁的操作。
因为Nacos-Java-Client的定位,所以Nacos-Java-Client会提供配置、服务实例的发布,删除,获取,订阅以及分布式锁的获取和释放,但不提供大范围的数据获取,如列举命名空间下所有配置列表, 列举命名空间下所有服务列表等操作。
如果需要大范围的获取数据,或者需要具有更高优先级的更新数据等运维能力,您需要使用Nacos的运维SDK。
0. 使用前说明
0.1. 先选择合适的接入方式
| 你要做什么 | 推荐入口 |
|---|---|
| 在 Java 应用中读取配置、监听配置、注册实例、订阅服务。 | 使用本文介绍的 Java SDK。 |
| 在 Java 应用中查询或订阅 MCP、Agent、Skill、Prompt、AgentSpec 等 AI 资源。 | 使用本文 AI 相关章节,并先阅读 AI 管理中心概述。 |
| 在 Go、Python 或其他语言中接入 Nacos。 | 阅读 SDK 概览,选择对应语言 SDK。 |
| 理解连接、重连、本地缓存、failover 和生命周期。 | 阅读 SDK 运行时。 |
| 通过 HTTP 查询少量已知配置或服务。 | 使用客户端 API。 |
| 发布配置、查询列表、管理命名空间、管理服务或执行运维操作。 | 使用运维 API或运维 SDK。 |
Java SDK 面向应用运行时。它会维护连接、监听、订阅、本地缓存和重连恢复。业务应用应优先复用 SDK 提供的能力,不建议直接拼接内部请求或依赖控制台 API。
0.2. 使用原则
- 一个 SDK 实例对应一个命名空间。访问多个命名空间时,请分别创建实例。
- 应用内尽量复用 SDK 实例,避免频繁创建客户端导致连接和线程资源浪费。
- 应用退出、热重载或替换客户端实例时,请调用
shutdown()释放资源。 - 配置监听的
Listener.receiveConfigInfo收到配置内容,应用按自己的逻辑完成刷新。 - 服务订阅返回的是运行时发现视图,可能受到健康状态、权重、保护阈值、cluster 和 selector 等因素影响。
- AI 资源受命名空间、版本、标签、发布状态和可见性影响。生产环境中使用 MCP、Agent、Skill、Prompt 等支持版本或标签的资源时,建议明确版本或标签,并处理资源不存在、不可见或版本变化的情况。
- AI 资源订阅按对应监听器返回内容或发现快照;应用应替换旧视图,并处理资源不可用事件。不要把所有订阅回调都当作需要再次查询的通知。
- 分布式锁属于实验性功能,生产使用前请先阅读分布式锁文档并完成充分验证。
1. 引用概述
1.1. Java 版本依赖
Nacos 的 Java SDK需要 JDK 1.8 及以上版本的Java运行环境。
1.2. Maven 坐标
<dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>3.3.0</version></dependency>1.2.1. 纯净版 Java SDK
注意:由于Nacos Java SDK在2.0版本后引入了gRPC,为了避免用户业务引入的gRPC版本不同导致冲突,使用了shaded技术将部分依赖直接封装进nacos-client中,导致nacos-client较大。 如果用户未自行引入gRPC或确认版本无冲突,希望使用纯净版的nacos-client以减小依赖,可以使用classifier来指定使用纯净版。
<properties> <!-- 2.1.2版本以上支持纯净版客户端 --> <nacos.version>3.3.0</nacos.version> </properties>
<dependencies> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>${nacos.version}</version> <!-- 指定纯净版SDK --> <classifier>pure</classifier> </dependency> <!-- 使用纯净版时必须要引入同版本nacos-api和nacos-common,否则可能出现运行时找不到类的问题 --> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-common</artifactId> <version>${nacos.version}</version> </dependency> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-api</artifactId> <version>${nacos.version}</version> </dependency> </dependencies>1.3. 升级兼容性
3.x 将默认命名空间 ID 从空字符串改为 public(参见 issue #9846)。3.0 客户端默认使用 public,在默认命名空间下连接老版本服务端时会不兼容。
升级前请确认:服务端已升级至 3.0 及以上,或未在默认命名空间下使用配置中心。
升级到 3.3 Java SDK 时,还需检查:
- AI 新代码使用第 2 节的资源子入口。已发布的 MCP、A2A、Skill、Prompt、AgentSpec 扁平方法保留兼容并标记为 Deprecated;通用 Agent 操作使用
aiService.agent()。 - SDK 指标已使用 Micrometer。应用需接入
MeterRegistry,并调整指标名、单位和告警,详见客户端指标迁移;仅保留旧simpleclient依赖不会自动导出指标。 - 纯净版的
nacos-client、nacos-api、nacos-common使用相同版本,依赖选择按应用运行环境核对。
1.4. JSON 依赖与适配
3.3 支持 Jackson 2 和 Jackson 3。默认 auto 使用运行时可用的适配器;两者均可用时选择 Jackson 3。Jackson 2 随普通依赖引入;使用 Jackson 3 时,应用需自行提供对应依赖,并满足该 Jackson 版本的 Java 要求。Java SDK 的 Java 8 最低要求不代表 Jackson 3 也支持 Java 8。
如需固定 Jackson 2,在 JVM 启动参数中设置:
-Dnacos.client.json.adapter=jackson2可选值为 auto、jackson2、jackson3。显式选择不可用的适配器,或没有任何可用适配器时会初始化失败;该选项是 JVM 系统属性,不是每个 SDK 实例的 Properties 参数。
下文序列化示例使用 com.alibaba.nacos.api.utils.json.JsonUtils。新代码优先使用这个中立入口;旧 JacksonUtils 的 Jackson 2 专属类型签名仍属于兼容接口,不能通过切换适配器把它们变成 Jackson 3 类型。
依赖配置、仅保留 Jackson 3 的接入方式、常见错误及设计说明,见 JSON 适配与 Jackson 2/3 接入。
2. 初始化SDK
Nacos 3.3 默认开启客户端鉴权。使用默认鉴权插件时,先创建用户并授予目标资源权限,再通过 Properties 配置地址、用户名和密码。SDK 会自动登录、携带并刷新 token。只有地址的初始化方式不能为默认鉴权提供完整身份。
下例及后续示例显式读取 NACOS_USERNAME、NACOS_PASSWORD 环境变量,运行前请设置为实际账号信息。其他鉴权插件的配置见配置访问凭据。
Properties properties = new Properties();properties.setProperty(PropertyKeyConst.SERVER_ADDR, "localhost:8848");properties.setProperty(PropertyKeyConst.NAMESPACE, "public");properties.setProperty(PropertyKeyConst.USERNAME, System.getenv("NACOS_USERNAME"));properties.setProperty(PropertyKeyConst.PASSWORD, System.getenv("NACOS_PASSWORD"));
ConfigService configService = NacosFactory.createConfigService(properties);NamingService namingService = NacosFactory.createNamingService(properties);LockService lockService = NacosLockFactory.createLockService(properties);AiService aiService = AiFactory.createAiService(properties);3.3 的 AI API 按资源取得子服务:
| 调用入口 | 返回类型 | 使用章节 |
|---|---|---|
aiService.mcp() | McpService | 第 6 章 |
aiService.agent() | AgentService | 第 7 章旧 A2A 兼容、第 11 章通用 Agent |
aiService.skill() | SkillService | 第 8 章 |
aiService.prompt() | PromptService | 第 9 章 |
aiService.agentSpec() | AgentSpecService | 第 10 章 |
以上接口位于 com.alibaba.nacos.api.ai,共享当前 AiService 的命名空间、连接和鉴权;统一调用 aiService.shutdown() 释放资源。下文使用子入口,已有扁平兼容调用可逐步迁移。通用 Agent 的搜索、发现、订阅、端点注册和定义发布不能直接在 AiService 上调用。
更多初始化时所涉及的参数配置,请参考Java SDK 配置参数。
注意:一个Nacos Java SDK实例只能用于获取同一个命名空间下的配置和服务,如果要获取不同的命名空间下的配置或服务,需要创建不同的Nacos Java SDK实例。
3. 配置管理 API
3.1. 获取配置
描述
用于服务启动的时候从 Nacos 获取配置。
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException;
ConfigQueryResult getConfig(GetConfigRequest request) throws NacosException;请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| dataId | string | 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节。 |
| group | string | 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过128字节。 |
| timeoutMs | long | 读取配置超时时间,单位 ms,推荐值 3000。 |
3.3 新增 getConfig(GetConfigRequest)。请求和结果模型位于 com.alibaba.nacos.api.config,命名空间沿用创建 SDK 时的配置。
| 请求字段 | 类型 | 说明 |
|---|---|---|
| dataId | String | 必填,配置 ID。 |
| group | String | 配置分组,空值使用 DEFAULT_GROUP。 |
| timeoutMs | long | 查询超时,单位毫秒;应显式设置,例如 5000。 |
| localMd5 | String | 可选,本地已有内容的 MD5。通常留空,由 SDK 管理条件查询及匹配内容。 |
返回值
| 参数类型 | 描述 |
|---|---|
| string | 配置值 |
请求对象重载返回 ConfigQueryResult,含 content、md5、configType、encryptedDataKey。配置不存在时 content 可为空;CAS 更新应使用返回的 md5,尤其不要对解密后的正文自行计算 MD5。
SDK 会处理 gRPC 查询的 Not-Modified 响应并还原内容。调用方仍读取结果对象,无需处理 HTTP 304;这也不表示所有 HTTP Config API 都支持条件查询。
请求示例
try { String serverAddr = "{serverAddr}"; String dataId = "{dataId}"; String group = "{group}"; Properties properties = new Properties(); properties.setProperty("username", System.getenv("NACOS_USERNAME")); properties.setProperty("password", System.getenv("NACOS_PASSWORD")); properties.put("serverAddr", serverAddr); ConfigService configService = NacosFactory.createConfigService(properties); String content = configService.getConfig(dataId, group, 5000); System.out.println(content);} catch (NacosException e) { e.printStackTrace();}请求对象用法如下,沿用第 2 节创建的 configService:
GetConfigRequest request = GetConfigRequest.builder() .dataId("{dataId}").group("{group}").timeoutMs(5000).build();ConfigQueryResult result = configService.getConfig(request);System.out.println(result.getContent());System.out.println(result.getMd5());异常说明
参数校验失败、读取配置超时或网络异常时,可能抛出 NacosException。
3.2. 监听配置
描述
如果希望 Nacos 推送配置变更,可以使用 Nacos 动态监听配置接口来实现。
void addListener(String dataId, String group, Listener listener) throws NacosException;请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| dataId | string | 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节。 |
| group | string | 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过128字节。 |
| listener | Listener | 监听器,配置变更进入监听器的回调函数。 |
返回值
无直接返回值。配置内容通过 Listener.receiveConfigInfo(String configInfo) 回调接收。需要同步获取当前配置并注册监听器时,可使用 getConfigAndSignListener。
请求示例
String serverAddr = "{serverAddr}";String dataId = "{dataId}";String group = "{group}";Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.put("serverAddr", serverAddr);ConfigService configService = NacosFactory.createConfigService(properties);String content = configService.getConfig(dataId, group, 5000);System.out.println(content);Listener listener = new Listener() { @Override public void receiveConfigInfo(String configInfo) { System.out.println("recieve1:" + configInfo); } @Override public Executor getExecutor() { return null; }};configService.addListener(dataId, group, listener);
// 测试让主线程不退出,因为订阅配置是守护线程,主线程退出守护线程就会退出。 正式代码中无需下面代码while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }}3.3. 删除监听
描述
取消监听配置,取消监听后配置不会再推送。
void removeListener(String dataId, String group, Listener listener);请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| dataId | string | 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节。 |
| group | string | 配置分组 |
| listener | Listener | 注册监听时使用的同一个监听器实例。 |
返回值
无。
使用示例
// Reuse the live configService and listener registered in section 3.2.configService.removeListener(dataId, group, listener);3.4. 发布配置
描述
用于通过程序自动发布 Nacos 配置,以便通过自动化手段降低运维成本。
注意:创建和修改配置时使用的同一个发布接口,当配置不存在时会创建配置,当配置已存在时会更新配置。
public boolean publishConfig(String dataId, String group, String content) throws NacosException;
public boolean publishConfig(String dataId, String group, String content, String type) throws NacosException;
PublishConfigResult publishConfig(PublishConfigRequest request) throws NacosException;请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| dataId | string | 配置 ID,采用类似 package.class(如 com.taobao.tc.refund.log.level)的命名规则保证全局唯一性。建议根据配置的业务含义来定义 class 部分。全部字符均为小写。只允许英文字符和 4 种特殊字符(“.”、“:”、“-”、“_”),不超过 256 字节。 |
| group | string | 配置分组,建议填写产品名:模块名(如 Nacos:Test)来保证唯一性。只允许英文字符和 4 种特殊字符(“.”、“:”、“-”、“_”),不超过 128 字节。 |
| content | string | 配置内容,受服务端 maxContent 及容量检查中的配置大小限制约束。 |
| type | string | @Since 1.4.1. 配置类型,见 com.alibaba.nacos.api.config.ConfigType,默认为TEXT |
3.3 新增 publishConfig(PublishConfigRequest),请求模型位于 com.alibaba.nacos.api.config,包含上述 dataId、group、content、type,以及可选的 casMd5。设置 casMd5 时执行 CAS;不匹配时发布失败,不覆盖已有内容。命名空间使用 SDK 上下文。
返回参数
| 参数类型 | 描述 |
|---|---|
| boolean | 是否发布成功 |
请求对象重载返回 PublishConfigResult:先检查 isSuccess(),失败时读取 getErrorCode() 和 getErrorMessage();成功时可读取 getMd5()。远端请求失败可能通过失败结果返回,本地参数校验或过滤器仍可能抛出异常,不能只依赖 catch 判断发布失败。
请求示例
try { // 初始化配置服务,控制台通过示例代码自动获取下面参数 String serverAddr = "{serverAddr}"; String dataId = "{dataId}"; String group = "{group}"; Properties properties = new Properties(); properties.setProperty("username", System.getenv("NACOS_USERNAME")); properties.setProperty("password", System.getenv("NACOS_PASSWORD")); properties.put("serverAddr", serverAddr); ConfigService configService = NacosFactory.createConfigService(properties); boolean isPublishOk = configService.publishConfig(dataId, group, "content"); System.out.println(isPublishOk);} catch (NacosException e) { e.printStackTrace();}请求对象支持一次查询后进行 CAS 发布,沿用第 2 节创建的 configService:
ConfigQueryResult current = configService.getConfig(GetConfigRequest.builder() .dataId("{dataId}").group("{group}").timeoutMs(5000).build());if (current.getContent() == null || current.getMd5() == null) { throw new IllegalStateException("Read an existing configuration before CAS publishing");}PublishConfigResult result = configService.publishConfig(PublishConfigRequest.builder() .dataId("{dataId}").group("{group}").content("new-content") .type("text").casMd5(current.getMd5()).build());if (!result.isSuccess()) { System.err.println(result.getErrorCode() + ": " + result.getErrorMessage());}异常说明
发布失败时,检查返回的布尔值或结果对象,同时处理参数校验、过滤器等环节可能抛出的 NacosException。
3.5. 删除配置
描述
用于通过程序自动删除 Nacos 配置,以便通过自动化手段降低运维成本。
注意: 当配置已存在时会删除该配置,当配置不存在时会直接返回成功消息。
public boolean removeConfig(String dataId, String group) throws NacosException;
RemoveConfigResult removeConfig(RemoveConfigRequest request) throws NacosException;请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| dataId | string | 配置 ID |
| group | string | 配置分组 |
返回参数
| 参数类型 | 描述 |
|---|---|
| boolean | 是否删除成功 |
3.3 新增的 RemoveConfigRequest 位于 com.alibaba.nacos.api.config,字段为 dataId 和 group;命名空间使用 SDK 上下文。返回 RemoveConfigResult,通过 isSuccess() 判断成功,失败时读取 getErrorCode() 和 getErrorMessage()。参数或远端调用异常仍需按 NacosException 处理。
请求示例
try { // 初始化配置服务,控制台通过示例代码自动获取下面参数 String serverAddr = "{serverAddr}"; String dataId = "{dataId}"; String group = "{group}"; Properties properties = new Properties(); properties.setProperty("username", System.getenv("NACOS_USERNAME")); properties.setProperty("password", System.getenv("NACOS_PASSWORD")); properties.put("serverAddr", serverAddr);
ConfigService configService = NacosFactory.createConfigService(properties); boolean isRemoveOk = configService.removeConfig(dataId, group); System.out.println(isRemoveOk);} catch (NacosException e) { e.printStackTrace();}请求对象用法如下,沿用第 2 节创建的 configService:
RemoveConfigResult result = configService.removeConfig(RemoveConfigRequest.builder() .dataId("{dataId}").group("{group}").build());if (!result.isSuccess()) { System.err.println(result.getErrorCode() + ": " + result.getErrorMessage());}异常说明
删除失败时,检查返回的布尔值或结果对象,并处理参数校验或远端调用可能抛出的 NacosException。
3.6. 带监听器的获取配置
描述
如果希望在程序首次启动获取配置时自行注册的Listener用于以后配置更新,建议您直接使用该接口。
该接口等价于先使用
getConfig之后再使用addListener。
String getConfigAndSignListener(String dataId, String group, long timeoutMs, Listener listener) throws NacosException;请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| dataId | string | 配置 ID,采用类似 package.class(如com.taobao.tc.refund.log.level)的命名规则保证全局唯一性,class 部分建议是配置的业务含义。全部字符小写。只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节。 |
| group | string | 配置分组,建议填写产品名:模块名(Nacos)保证唯一性,只允许英文字符和4种特殊字符(”.”、”:”、”-”、”_”),不超过128字节。 |
| timeoutMs | long | 读取配置超时时间,单位 ms,推荐值 3000。 |
| listener | Listener | 监听器,配置变更进入监听器的回调函数。 |
返回值
| 参数类型 | 描述 |
|---|---|
| string | 配置值 |
请求示例
try { String serverAddr = "{serverAddr}"; String dataId = "{dataId}"; String group = "{group}"; Properties properties = new Properties(); properties.setProperty("username", System.getenv("NACOS_USERNAME")); properties.setProperty("password", System.getenv("NACOS_PASSWORD")); properties.put("serverAddr", serverAddr); ConfigService configService = NacosFactory.createConfigService(properties); String content = configService.getConfigAndSignListener(dataId, group, 5000, new Listener() { @Override public void receiveConfigInfo(String configInfo) { System.out.println("recieve1:" + configInfo); } @Override public Executor getExecutor() { return null; } }); System.out.println(content);} catch (NacosException e) { e.printStackTrace();}异常说明
读取配置超时或网络异常,抛出 NacosException 异常。
3.7. 带Compare-And-Swap(CAS)的发布配置
描述
直接使用publishConfig进行配置发布时,可能存在不同进程间并发的配置覆盖问题,此时可以使用带Compare-And-Swap(CAS)的发布配置API,来保证不会此类情形。
注意:创建和修改配置时使用的同一个发布接口,当配置不存在时会创建配置,当配置已存在时会更新配置。
boolean publishConfigCas(String dataId, String group, String content, String casMd5) throws NacosException;
boolean publishConfigCas(String dataId, String group, String content, String casMd5, String type) throws NacosException;请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| dataId | string | 配置 ID,采用类似 package.class(如 com.taobao.tc.refund.log.level)的命名规则保证全局唯一性。建议根据配置的业务含义来定义 class 部分。全部字符均为小写。只允许英文字符和 4 种特殊字符(“.”、“:”、“-”、“_”),不超过 256 字节。 |
| group | string | 配置分组,建议填写产品名:模块名(如 Nacos:Test)来保证唯一性。只允许英文字符和 4 种特殊字符(“.”、“:”、“-”、“_”),不超过 128 字节。 |
| content | string | 配置内容,受服务端 maxContent 及容量检查中的配置大小限制约束。 |
| casMd5 | string | 前配置内容的md5 |
| type | string | 配置类型,见 com.alibaba.nacos.api.config.ConfigType,默认为TEXT |
返回参数
| 参数类型 | 描述 |
|---|---|
| boolean | 是否发布成功 |
请求示例
try { // 初始化配置服务,控制台通过示例代码自动获取下面参数 String serverAddr = "{serverAddr}"; String dataId = "{dataId}"; String group = "{group}"; String oldContent = "oldContent"; String oldContentMd5 = "63fb636909f1ebad67110e49117e6de4"; Properties properties = new Properties(); properties.setProperty("username", System.getenv("NACOS_USERNAME")); properties.setProperty("password", System.getenv("NACOS_PASSWORD")); properties.put("serverAddr", serverAddr); ConfigService configService = NacosFactory.createConfigService(properties); // 首次发布,casMd5传入null。 boolean isPublishOk = configService.publishConfigCas(dataId, group, oldContent, null); System.out.println(isPublishOk); // old Md5 正确,变成成功 isPublishOk = configService.publishConfigCas(dataId, group, "newContent", oldContentMd5); System.out.println(isPublishOk); // old Md5 错误,变成失败 isPublishOk = configService.publishConfigCas(dataId, group, "newContent2", oldContentMd5); System.out.println(isPublishOk);} catch (NacosException e) { e.printStackTrace();}异常说明
读取配置超时或网络异常,抛出 NacosException 异常。
3.8. 配置模糊订阅
描述
通过fuzzyWatch接口可以对指定分组group和配置dataId规则的配置进行批量订阅,
可通过*进行前缀模糊,后缀模糊,双边模糊匹配。
模糊订阅功能仅会推送配置的新增以及删除事件,并不会直接推送配置变更的内容,可在配置模糊订阅的监听器中结合addListener接口实现配置内容的变更监听。
处于稳定性考虑,Nacos对模糊订阅的规则数量以及单个规则匹配的配置数量有上限保护。具体参照配置模糊订阅容量保护机制一节。
/** * 订阅当前命名空间下指定分组group规则及dataId规则下所有配置的变更事件 * 模糊订阅的列表将以异步的方式通过watcher回调 * @param dataIdPattern dataId匹配规则 * @param groupNamePattern 分组匹配规则 * @param watcher 模糊订阅监听器 */void fuzzyWatch(String dataIdPattern, String groupNamePattern, FuzzyWatchEventWatcher watcher);
/** * 订阅当前命名空间下指定分组group规则及dataId规则下所有配置的变更事件,并以Future模式获取规则当前匹配的配置列表 * 模糊订阅的列表将以异步的方式通过watcher回调 * @param dataIdPattern dataId匹配规则 * @param groupNamePattern 分组group匹配规则 * @param watcher 模糊订阅监听器 * @return Future 可通过future等待配置异步推送结果 */Future<Set<String>> fuzzyWatchWithGroupKeys(String dataIdPattern, String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
/** * 取消订阅当前命名空间下指定分组group规则及dataId规则下所有配置的变更事件 * @param dataIdPattern dataId匹配规则 * @param groupNamePattern 分组group匹配规则 * @param watcher 需要移除的模糊订阅watcher */void cancelFuzzyWatch(String dataIdPattern, String groupNamePattern, FuzzyWatchEventWatcher watcher);
/** * 订阅当前命名空间下指定分组group规则下所有配置的变更事件 * * @param groupNamePattern 分组匹配规则 * @param watcher 模糊订阅监听器 */void fuzzyWatch(String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
/** * 订阅当前命名空间下指定分组group规则下所有配置的变更事件,可通过Future获取当前匹配的所有配置列表 * * @param groupNamePattern 分组group匹配规则 * @param watcher 模糊订阅监听器 * @return Future 可通过future等待配置异步推送结果 */Future<Set<String>> fuzzyWatchWithGroupKeys(String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
/** * 取消订阅当前命名空间下指定分组group规则及dataId规则下所有配置的变更事件 * * @param groupNamePattern 分组group匹配规则 * @param watcher 需要移除的模糊订阅watcher */void cancelFuzzyWatch(String groupNamePattern, FuzzyWatchEventWatcher watcher) ;请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| dataIdPattern | string | 配置ID匹配规则,支持a.前缀模糊匹配(如,mydataId*) b.后缀模糊匹配(如*mydatdId),c.双边模糊匹配(如*mydatadId*) |
| groupNamePattern | string | 配置分组匹配规则,支持a.前缀模糊匹配(如 mygroup*) b.后缀模糊匹配(如 *mygroup),c.双边模糊匹配(如 *mygroup*) |
| watcher | FuzzyWatchEventWatcher | 模糊订阅监听器 |
FuzzyWatchEventWatcher模糊订阅监听器
| 方法名 | 方法参数类型 | 描述 |
|---|---|---|
| onEvent | ConfigFuzzyWatchChangeEvent | 模糊订阅回调事件对象 |
| getExecutor | void | 可指定执行回调事件的线程池,如果为空,将以nacos推送线程中执行回调 |
ConfigFuzzyWatchChangeEvent模糊订阅事件
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| dataId | string | 变更的配置dataId |
| group | string | 变更的配置分组group |
| namespace | string | 变更的配命名空间 |
| changedType | string | 变更类型,表示客户端接收到的配置变更类型,包含ADD_CONFIG-新增配置,DELETE_CONFIG-移除配置 |
| syncType | string | 触发变更的类型,包含FUZZY_WATCH_INIT_NOTIFY-初始化推送,FUZZY_WATCH_DIFF_SYNC_NOTIFY-变更对账触发,FUZZY_WATCH_RESOURCE_CHANGED-配置变更推送 |
返回参数
| 参数类型 | 描述 |
|---|---|
| Future<Set | 返可获取当前匹配的配置列表的future对象,当规则匹配的配置列表已经推送到客户端时,可通过future对象获取配置列表 *注意:当触发容量保护时,返回的配置列表可能不全 |
//返回的参数为groupKey列表,可通过GroupKey工具类获取dataId,group及namespaceString[] groupKeyItems = GroupKey.parseKey(String groupKey);String dataId=groupKeyItems[0];String group=groupKeyItems[1];String namespace=groupKeyItems[2];配置模糊订阅容量保护机制
处于稳定性角度考虑,避免过多的规则及规则匹配的配置数量导致服务端内存压力以及对客户端造成推送风暴,Nacos在两个层面对模糊订阅功能设计了容量保护机制,当超过上限时,模糊订阅的推送将被抑制。
- 模糊订阅规则数量上限保护 ,默认的模糊订阅规则数量上限为20,可通过参数nacos.config.fuzzy.watch.max.pattern.count调整上限。
- 单个模糊订阅规则匹配的配置数量上限保护, 默认单个模糊订阅规则匹配的配置数量上限为500,可通过nacos.config.fuzzy.watch.max.pattern.match.config.count调整上限。
在fuzzyWatch接口中注册模糊订阅监听器可同时实现FuzzyWatchLoadWatcher负载监听器感知容量保护机制的发生。
FuzzyWatchLoadWatcher模糊订阅负载监听器
| 方法名 | 描述 |
|---|---|
| onPatternOverLimit | 当前模糊订阅规则因超过上限,推送被抑制时触发 |
| onConfigReachUpLimit | 当前模糊订阅规则匹配的配置数量达到上限,推送被抑制时触发 |
*注意:
- 当触发容量保护时,通过fuzzyWatchWithGroupKeys返回的配置列表可能不是完整的配置列表。
- 当触发配置数量上限保护时,配置删除的事件也可能因保护机制而导致无法推送。
请求示例
try { // 初始化配置服务,控制台通过示例代码自动获取下面参数 String serverAddr = "{serverAddr}"; String dataIdPattern = "testDataId*"; String groupPattern = "group*"; Properties properties = new Properties(); properties.setProperty("username", System.getenv("NACOS_USERNAME")); properties.setProperty("password", System.getenv("NACOS_PASSWORD")); properties.put("serverAddr", serverAddr); properties.put("namespace", "mynamespaceId");
ConfigService configService = NacosFactory.createConfigService(properties); Future<Set<String>> fuzzyWatchFuture = configService.fuzzyWatchWithGroupKeys(dataIdPattern, groupPattern, new AbstractFuzzyWatchEventWatcher() { @Override public void onEvent(ConfigFuzzyWatchChangeEvent event) { String changedType= event.getChangedType(); String syncType= event.getSyncType(); String groupChanged = event.getGroup(); String dataIdChanged = event.getDataId(); String namespace = event.getNamespace(); //do something }
@Override public void onPatternOverLimit() { System.out.println("pattern count over limit"); //do something... }
@Override public void onConfigReachUpLimit() { System.out.println("pattern match config count reach to up limit"); //do something... } });
Set<String> matchGroupKeys = fuzzyWatchFuture.get(); System.out.println("get group keys count:"+matchGroupKeys.size());
} catch (NacosException e) { e.printStackTrace();}3.9. 获取配置(含结果对象)
描述
用于从 Nacos 获取配置并得到包含配置内容与 MD5 等元数据的结果对象,便于后续 CAS 发布等操作。该 API 的起始版本为 3.0。
ConfigQueryResult getConfigWithResult(String dataId, String group, long timeoutMs) throws NacosException;请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| dataId | string | 配置 ID,采用类似 package.class 的命名规则保证全局唯一性,只允许英文字符和 4 种特殊字符(”.”、”:”、”-”、”_”),不超过 256 字节。 |
| group | string | 配置分组,建议填写产品名:模块名保证唯一性,只允许英文字符和 4 种特殊字符,不超过 128 字节。 |
| timeoutMs | long | 读取配置超时时间,单位 ms,推荐值 3000。 |
返回值
| 参数类型 | 描述 |
|---|---|
| ConfigQueryResult | 包含配置内容(content)、MD5(md5)等字段,可用于 带 CAS 的发布配置。 |
请求示例
try { String serverAddr = "{serverAddr}"; String dataId = "{dataId}"; String group = "{group}"; Properties properties = new Properties(); properties.setProperty("username", System.getenv("NACOS_USERNAME")); properties.setProperty("password", System.getenv("NACOS_PASSWORD")); properties.put("serverAddr", serverAddr); ConfigService configService = NacosFactory.createConfigService(properties); ConfigQueryResult result = configService.getConfigWithResult(dataId, group, 5000); String content = result.getContent(); String md5 = result.getMd5(); System.out.println(content);} catch (NacosException e) { e.printStackTrace();}异常说明
读取配置超时或网络异常时,抛出 NacosException。
3.10. 获取服务端状态
描述
获取当前配置中心服务端状态。
String getServerStatus();请求参数
无。
返回值
| 参数类型 | 描述 |
|---|---|
| String | 服务端状态。 |
请求示例
ConfigService configService = NacosFactory.createConfigService("{serverAddr}");String status = configService.getServerStatus();System.out.println(status);3.11. 添加配置过滤器
描述
添加配置过滤器,用于在获取/发布配置时对请求或响应进行过滤。建议通过继承 com.alibaba.nacos.api.config.filter.AbstractConfigFilter 扩展过滤器。该 API 的起始版本为 2.3.0。
void addConfigFilter(IConfigFilter configFilter);请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| configFilter | IConfigFilter | 配置过滤器实例,建议使用 AbstractConfigFilter 子类。 |
返回值
无。
请求示例
ConfigService configService = NacosFactory.createConfigService("{serverAddr}");configService.addConfigFilter(new AbstractConfigFilter() { @Override public void init(Properties properties) {} @Override public void doFilter(IConfigRequest request, IConfigResponse response, IConfigFilterChain chain) throws NacosException { // 过滤逻辑 chain.doFilter(request, response); } @Override public int getOrder() { return 0; } @Override public String getFilterName() { return "myFilter"; }});4. 服务发现API
学习提示:使用服务发现 API 注册实例时,客户端进程退出后 Nacos 会将该实例摘除,控制台将看不到刚注册的实例。学习或调试时可在注册后使用
Thread.sleep()等方式保持进程运行,以便在 Nacos 控制台确认注册是否成功。
4.1. 注册实例
描述
注册一个实例到服务。
由于同一个Nacos Client实例,仅能向一个服务注册一个实例;若同一个Nacos Client实例多次向同一个服务注册实例,后注册的实例将会覆盖先注册的实例。 若有存在代理注册的场景,请使用批量注册服务实例
void registerInstance(String serviceName, String ip, int port) throws NacosException;
void registerInstance(String serviceName, String groupName, String ip, int port) throws NacosException;
void registerInstance(String serviceName, String ip, int port, String clusterName) throws NacosException;
void registerInstance(String serviceName, String groupName, String ip, int port, String clusterName) throws NacosException;
void registerInstance(String serviceName, Instance instance) throws NacosException;
void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| ip | 字符串 | 服务实例IP | 无,必填 |
| port | int | 服务实例port | 无,必填 |
| clusterName | 字符串 | 集群名 | DEFAULT |
| instance | 参见代码注释 | 实例属性 | 无,必填 |
返回参数
无
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));
// 以下注册请求所造成的结果均一致, 注册分组名为`DEFAULT_GROUP`, 服务名为`nacos.test.service`的实例,实例的ip为`127.0.0.1`, port为`8848`, clusterName为`DEFAULT`.naming.registerInstance("nacos.test.service", "127.0.0.1", 8848);naming.registerInstance("nacos.test.service", "DEFAULT_GROUP", "127.0.0.1", 8848);naming.registerInstance("nacos.test.service", "127.0.0.1", 8848, "DEFAULT");naming.registerInstance("nacos.test.service", "DEFAULT_GROUP", "127.0.0.1", 8848, "DEFAULT");Instance instance = new Instance();instance.setIp("127.0.0.1");instance.setPort(8848);instance.setClusterName("DEFAULT");naming.registerInstance("nacos.test.service", instance);naming.registerInstance("nacos.test.service", "DEFAULT_GROUP", instance);
// 保持进程不退出,便于在 Nacos 控制台查看已注册的实例(学习/调试用)Thread.sleep(300000); // 例如保持 5 分钟4.2. 注销实例
描述
删除服务下的一个实例。
若该服务是通过批量注册服务实例进行注册,使用注销实例进行注销时,将注销所有批量注册的实例。 若仅希望注销部分批量注册的实例,请使用批量注销服务实例
void deregisterInstance(String serviceName, String ip, int port) throws NacosException;
void deregisterInstance(String serviceName, String groupName, String ip, int port) throws NacosException;
void deregisterInstance(String serviceName, String ip, int port, String clusterName) throws NacosException;
void deregisterInstance(String serviceName, String groupName, String ip, int port, String clusterName) throws NacosException;
void deregisterInstance(String serviceName, Instance instance) throws NacosException;
void deregisterInstance(String serviceName, String groupName, Instance instance);请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| ip | 字符串 | 服务实例IP | 无,必填 |
| port | int | 服务实例port | 无,必填 |
| clusterName | 字符串 | 集群名 | DEFAULT |
| instance | 参见代码注释 | 实例属性 | 无,必填 |
返回参数
无
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));// 以下注销请求所造成的结果均一致, 注销分组名为`DEFAULT_GROUP`, 服务名为`nacos.test.service`的实例,实例的ip为`127.0.0.1`, port为`8848`, clusterName为`DEFAULT`.naming.deregisterInstance("nacos.test.service", "127.0.0.1", 8848);naming.deregisterInstance("nacos.test.service", "DEFAULT_GROUP", "127.0.0.1", 8848);naming.deregisterInstance("nacos.test.service", "127.0.0.1", 8848, "DEFAULT");naming.deregisterInstance("nacos.test.service", "DEFAULT_GROUP", "127.0.0.1", 8848, "DEFAULT");Instance instance = new Instance();instance.setIp("127.0.0.1");instance.setPort(8848);instance.setClusterName("DEFAULT");naming.deregisterInstance("nacos.test.service", instance);naming.deregisterInstance("nacos.test.service", "DEFAULT_GROUP", instance);4.3. 获取全部实例
描述
获取服务下的所有实例。
List<Instance> getAllInstances(String serviceName) throws NacosException;
List<Instance> getAllInstances(String serviceName, String groupName) throws NacosException;
List<Instance> getAllInstances(String serviceName, boolean subscribe) throws NacosException;
List<Instance> getAllInstances(String serviceName, String groupName, boolean subscribe) throws NacosException;
List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException;
List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters) throws NacosException;
List<Instance> getAllInstances(String serviceName, List<String> clusters, boolean subscribe) throws NacosException;
List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters, boolean subscribe) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| subscribe | Boolean | 是否订阅服务,为true时将会订阅该服务,同时查询优先通过内存缓存;为false时将直接查询Nacos Server | true |
| clusters | 字符串列表 | 实例的clusterName,空列表时将查询所有实例。 | 空列表 |
返回参数
List<Instance> 实例列表。
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));// 以下查询请求所造成的结果均一致.System.out.println(naming.getAllInstances("nacos.test.service"));System.out.println(naming.getAllInstances("nacos.test.service", "DEFAULT_GROUP"));System.out.println(naming.getAllInstances("nacos.test.service", true));System.out.println(naming.getAllInstances("nacos.test.service", "DEFAULT_GROUP", true));System.out.println(naming.getAllInstances("nacos.test.service", new ArrayList<>()));System.out.println(naming.getAllInstances("nacos.test.service", "DEFAULT_GROUP", new ArrayList<>()));System.out.println(naming.getAllInstances("nacos.test.service", new ArrayList<>(), true));System.out.println(naming.getAllInstances("nacos.test.service", "DEFAULT_GROUP", new ArrayList<>(), true));4.4. 获取健康或不健康实例列表
描述
根据条件获取过滤后的实例列表。
List<Instance> selectInstances(String serviceName, boolean healthy) throws NacosException;
List<Instance> selectInstances(String serviceName, String groupName, boolean healthy) throws NacosException;
List<Instance> selectInstances(String serviceName, boolean healthy, boolean subscribe) throws NacosException;
List<Instance> selectInstances(String serviceName, String groupName, boolean healthy, boolean subscribe) throws NacosException;
List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy) throws NacosException;
List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters, boolean healthy) throws NacosException;
List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy, boolean subscribe) throws NacosException;
List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters, boolean healthy, boolean subscribe) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| subscribe | Boolean | 是否订阅服务,为true时将会订阅该服务,同时查询优先通过内存缓存;为false时将直接查询Nacos Server | true |
| clusters | 字符串列表 | 实例的clusterName,空列表时将查询所有实例。 | 空列表 |
| healthy | boolean | 是否健康,为true时仅会返回健康的实例列表,反之则返回不健康的实例列表。 | true |
返回参数
List<Instance> 实例列表。
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));// 以下查询请求所造成的结果均一致.System.out.println(naming.selectInstances("nacos.test.service", true));System.out.println(naming.selectInstances("nacos.test.service", "DEFAULT_GROUP", true));System.out.println(naming.selectInstances("nacos.test.service", true, true));System.out.println(naming.selectInstances("nacos.test.service", "DEFAULT_GROUP", true, true));System.out.println(naming.selectInstances("nacos.test.service", new ArrayList<>(), true));System.out.println(naming.selectInstances("nacos.test.service", "DEFAULT_GROUP", new ArrayList<>(), true));System.out.println(naming.selectInstances("nacos.test.service", new ArrayList<>(), true, true));System.out.println(naming.selectInstances("nacos.test.service", "DEFAULT_GROUP", new ArrayList<>(), true, true));4.5. 获取一个健康实例
描述
根据负载均衡算法随机获取一个健康实例。
Instance selectOneHealthyInstance(String serviceName) throws NacosException;
Instance selectOneHealthyInstance(String serviceName, String groupName) throws NacosException;
Instance selectOneHealthyInstance(String serviceName, boolean subscribe) throws NacosException;
Instance selectOneHealthyInstance(String serviceName, String groupName, boolean subscribe) throws NacosException;
Instance selectOneHealthyInstance(String serviceName, List<String> clusters) throws NacosException;
Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters) throws NacosException;
Instance selectOneHealthyInstance(String serviceName, List<String> clusters, boolean subscribe) throws NacosException;
Instance selectOneHealthyInstance(String serviceName, String groupName, List<String> clusters, boolean subscribe) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| subscribe | Boolean | 是否订阅服务,为true时将会订阅该服务,同时查询优先通过内存缓存;为false时将直接查询Nacos Server | true |
| clusters | 字符串列表 | 实例的clusterName,空列表时将查询所有实例。 | 空列表 |
返回参数
Instance 实例。
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));// 以下查询请求所造成的结果均一致.System.out.println(naming.selectOneHealthyInstance("nacos.test.service"));System.out.println(naming.selectOneHealthyInstance("nacos.test.service", "DEFAULT_GROUP"));System.out.println(naming.selectOneHealthyInstance("nacos.test.service", true));System.out.println(naming.selectOneHealthyInstance("nacos.test.service", "DEFAULT_GROUP", true));System.out.println(naming.selectOneHealthyInstance("nacos.test.service", new ArrayList<>()));System.out.println(naming.selectOneHealthyInstance("nacos.test.service", "DEFAULT_GROUP", new ArrayList<>()));System.out.println(naming.selectOneHealthyInstance("nacos.test.service", new ArrayList<>(), true));System.out.println(naming.selectOneHealthyInstance("nacos.test.service", "DEFAULT_GROUP", new ArrayList<>(), true));4.6. 监听服务
描述
监听服务下的实例列表变化。
void subscribe(String serviceName, EventListener listener) throws NacosException;
void subscribe(String serviceName, String groupName, EventListener listener) throws NacosException;
void subscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException;
void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| clusters | 字符串列表 | 实例的clusterName,空列表时将查询所有实例。 | 空列表 |
| listener | EventListener | 回调listener | 无,必填 |
返回参数
无
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));EventListener serviceListener = event -> { if (event instanceof NamingEvent) { System.out.println(((NamingEvent) event).getServiceName()); System.out.println(((NamingEvent) event).getInstances()); }};naming.subscribe("nacos.test.service", serviceListener);naming.subscribe("nacos.test.service", "DEFAULT_GROUP", serviceListener);naming.subscribe("nacos.test.service", new ArrayList<>(), serviceListener);naming.subscribe("nacos.test.service", "DEFAULT_GROUP", new ArrayList<>(), serviceListener);使用自定义线程池进行异步监听
Nacos 支持使用自定义线程池进行异步监听回调,只需要将EventListener更换为AbstractEventListener,并实现Executor getExecutor()方法来返回自定义的线程池,Nacos Client将在服务发生变更时使用该线程池进行异步回调。
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));ExecutorService executorService = Executors.newFixedThreadPool(1);EventListener serviceListener = new AbstractEventListener() { @Override public void onEvent(Event event) { if (event instanceof NamingEvent) { System.out.println(((NamingEvent) event).getServiceName()); System.out.println(((NamingEvent) event).getInstances()); } }
@Override public Executor getExecutor() { return executorService; }};naming.subscribe("nacos.test.service", serviceListener);监听服务变化的差值
Nacos 从2.4.0版本你开始,支持监听服务变化的差值,即和之前相比,有哪些实例被新增,移除和修改,只需要将EventListener更换为AbstractNamingChangeListener,实现onChange方法即可。onChange中会传入NamingChangeEvent,其中InstancesDiff记录了此次通知和之前相比的实例变化。
同时为了防止差值的错误和异常,NamingChangeEvent仍然可以通过getInstances方法获取最终的服务实例列表。
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));ExecutorService executorService = Executors.newFixedThreadPool(1);EventListener serviceListener = new AbstractNamingChangeListener() { @Override public void onChange(NamingChangeEvent event) { if (event.isAdded()) { System.out.println(event.getAddedInstances()); } if (event.isRemoved()) { System.out.println(event.getRemovedInstances()); } if (event.isModified()) { System.out.println(event.getModifiedInstances()); } }
@Override public Executor getExecutor() { return executorService; }};naming.subscribe("nacos.test.service", serviceListener);4.7. 取消监听服务
描述
取消监听服务下的实例列表变化。
void unsubscribe(String serviceName, EventListener listener) throws NacosException;
void unsubscribe(String serviceName, String groupName, EventListener listener) throws NacosException;
void unsubscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException;
void unsubscribe(String serviceName, String groupName, List<String> clusters, EventListener listener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| clusters | 字符串列表 | 实例的clusterName,空列表时将查询所有实例。 | 空列表 |
| listener | EventListener | 回调listener | 无,必填 |
注意:取消监听服务时,需要使用进行订阅时的
listener进行取消监听,否则可能造成取消监听失败。
返回参数
无
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));EventListener serviceListener = event -> {};naming.subscribe("nacos.test.service", serviceListener);naming.unsubscribe("nacos.test.service", serviceListener);naming.unsubscribe("nacos.test.service", "DEFAULT_GROUP", serviceListener);naming.unsubscribe("nacos.test.service", new ArrayList<>(), serviceListener);naming.unsubscribe("nacos.test.service", "DEFAULT_GROUP", new ArrayList<>(), serviceListener);4.8. 批量注册服务实例
描述
注册一系列实例到指定服务。
由于同一个Nacos Client实例,仅能向一个服务注册一个实例;若同一个Nacos Client实例多次向同一个服务注册实例,后注册的实例将会覆盖先注册的实例。 考虑到社区存在代理注册的场景:如Nacos-Sync, Proxy-Registry等,需要在一个客户端中注册同一个服务的不同实例,社区新增了批量注册服务实例的功能。
void batchRegisterInstance(String serviceName, String groupName, List<Instance> instances) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| instances | Instance的List | 服务实例列表 | 无,必填 |
返回参数
无
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));
Instance instance1 = new Instance();instance1.setIp("127.0.0.1");instance1.setPort(8848);instance1.setClusterName("DEFAULT");
Instance instance2 = new Instance();instance2.setIp("127.0.0.1");instance2.setPort(9848);instance2.setClusterName("DEFAULT");
List<Instance> instances = new ArrayList<>(2);instances.add(instance1);instances.add(instance2);
naming.batchRegisterInstance("nacos.test.service", "DEFAULT_GROUP", instances);4.9. 批量注销服务实例
描述
从指定服务中注销一系列实例。
针对使用了批量注册服务实例的用户设计,允许用户选择一部分或全部批量注册的实例进行注销。
void batchDeregisterInstance(String serviceName, String groupName, List<Instance> instances) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| instances | Instance的List | 服务实例列表 | 无,必填 |
返回参数
无
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));
Instance instance1 = new Instance();instance1.setIp("127.0.0.1");instance1.setPort(8848);instance1.setClusterName("DEFAULT");
Instance instance2 = new Instance();instance2.setIp("127.0.0.1");instance2.setPort(9848);instance2.setClusterName("DEFAULT");
List<Instance> instances = new ArrayList<>(2);instances.add(instance1);instances.add(instance2);
naming.batchRegisterInstance("nacos.test.service", "DEFAULT_GROUP", instances);naming.batchDeregisterInstance("nacos.test.service", "DEFAULT_GROUP", instances);4.10. 带选择器的监听服务
描述
使用自定义逻辑的选择器,监听服务下的实例列表变化,当服务列表发生变化时,会使用自定义的选择器进行过滤,当过滤后的数据仍然有变化时,才会进行回调通知。
void subscribe(String serviceName, NamingSelector selector, EventListener listener) throws NacosException;
void subscribe(String serviceName, String groupName, NamingSelector selector, EventListener listener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| clusters | 字符串列表 | 实例的clusterName,空列表时将查询所有实例。 | 空列表 |
| selector | NamingSelector | 自定义的数据选择器 | 无,必填 |
| listener | EventListener | 回调listener | 无,必填 |
返回参数
无
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));EventListener serviceListener = event -> { if (event instanceof NamingEvent) { System.out.println(((NamingEvent) event).getServiceName()); System.out.println(((NamingEvent) event).getInstances()); }};// 只会选择订阅ip为`127.0`开头的实例。NamingSelector selector = NamingSelectorFactory.newIpSelector("127.0.*");naming.subscribe("nacos.test.service", "DEFAULT_GROUP", selector, serviceListener);预设提供的数据选择器
Nacos Client 提供了预设的多种数据选择器以供默认场景下使用:
- Cluster选择器,
NamingSelectorFactory.newClusterSelector(Collection<String> clusters), 当订阅服务时传入了clusters参数,Nacos Client将自动使用该数据选择器。 - Ip选择器,
NamingSelectorFactory.newClusterSelector(String ipRegex),当实例的ip满足传入的ipRegex时,才会被通知回调。 - 元数据选择器,
NamingSelectorFactory.newMetadataSelector(Map<String, String> metadata),当实例的元数据包含所有传入选择器的metadata时,才会被通知回调。 - 任意元数据选择器,
NamingSelectorFactory.newMetadataSelector(Map<String, String> metadata, false),当实例的元数据包含任意一对传入选择器的metadata时,才会被通知回调。
开发自定义数据选择器
多数情况下, 开发自定义数据选择器只需要创建DefaultNamingSelector即可,在构建时传入一个Predicate<Instance> filter作为单个实例是否满足您过滤条件的结果,类似Java中stream的filter方法,如此您仅需要考虑单个实例的过滤条件即可。
若是DefaultNamingSelector无法满足需求,您需要实现NamingSelector接口,根据传入的NamingContext进行复杂的逻辑校验,最后输出NamingResult给Nacos Client。
4.11. 取消带选择器的监听服务
描述
使用自定义逻辑的选择器进行监听服务下的实例列表变化,那么在取消监听时需要使用取消带选择器的监听服务的API才能正确取消监听。
注意:取消监听时需要传入监听时使用的selector和listener,否则可能导致取消监听失败。
void unsubscribe(String serviceName, NamingSelector selector, EventListener listener) throws NacosException;
void unsubscribe(String serviceName, String groupName, NamingSelector selector, EventListener listener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serviceName | 字符串 | 服务名 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
| clusters | 字符串列表 | 实例的clusterName,空列表时将查询所有实例。 | 空列表 |
| selector | NamingSelector | 自定义的数据选择器 | 无,必填 |
| listener | EventListener | 回调listener | 无,必填 |
返回参数
无
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));EventListener serviceListener = event -> { if (event instanceof NamingEvent) { System.out.println(((NamingEvent) event).getServiceName()); System.out.println(((NamingEvent) event).getInstances()); }};// 只会选择订阅ip为`127.0`开头的实例。NamingSelector selector = NamingSelectorFactory.newIpSelector("127.0.*");naming.subscribe("nacos.test.service", "DEFAULT_GROUP", selector, serviceListener);naming.unsubscribe("nacos.test.service", "DEFAULT_GROUP", selector, serviceListener);4.12. 分页获取服务列表
描述
通过分页的方式获取当前客户端所在命名空间的服务列表。
ListView<String> getServicesOfServer(int pageNo, int pageSize) throws NacosException;
ListView<String> getServicesOfServer(int pageNo, int pageSize, String groupName) throws NacosException;注意:带
AbstractSelector的getServicesOfServer方法已废弃,不建议使用,本文档不再列出;后续会在 API 定义中标记为@Deprecated。请仅使用上述两参数或三参数重载。
请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| pageNo | int | 分页序号 | 无,必填 |
| pageSize | int | 分页中每页的服务个数 | 无,必填 |
| groupName | 字符串 | 分组名 | DEFAULT_GROUP |
返回参数
服务名列表: ListView
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));// 等价于`naming.getServicesOfServer(1, 10, "DEFAULT_GROUP");`ListView<String> result = naming.getServicesOfServer(1, 10);System.out.println(result.getCount());System.out.println(result.getData());4.13. 获取当前客户端所监听的服务列表
描述
获取当前客户端所的所有服务列表
List<ServiceInfo> getSubscribeServices() throws NacosException;请求参数
无
返回参数
服务列表: List
请求示例
NamingService naming = NamingFactory.createNamingService(System.getProperty("serveAddr"));System.out.println(naming.getSubscribeServices());4.14. 服务模糊订阅
描述
通过fuzzyWatch接口可以对符指定group和serviceName规则的服务进行批量订阅, 可通过*进行前缀模糊,后缀模糊,双边模糊匹配。
模糊订阅功能仅会推送服务的新增以及删除事件,并不会直接推送服务下实例列表,可在服务模糊订阅的监听器中结合subscribe接口实现服务下实例列表的变更监听。
处于稳定性考虑,Nacos对模糊订阅的规则数量以及单个规则匹配的服务数量有上限保护。具体参照服务模糊容量保护机制一节。
/** * 订阅当前命名空间下指定分组group规则及服务名规则下所有服务的变更事件 * * @param serviceNamePattern 服务名匹配规则 * @param groupNamePattern 分组匹配规则 * @param watcher 模糊订阅监听器 */void fuzzyWatch(String serviceNamePattern, String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
/** * 订阅当前命名空间下指定分组group规则及服务serviceName规则下所有服务的变更事件,并以Future模式获取规则当前匹配的服务列表 * 模糊订阅的列表将以异步的方式通过watcher回调 * @param serviceNamePattern 服务serviceName匹配规则 * @param groupNamePattern 分组group匹配规则 * @param watcher 模糊订阅监听器 * @return Future 可通过future等待配置异步推送结果 */Future<ListView<String>> fuzzyWatchWithServiceKeys(String serviceNamePattern, String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
/** * 取消订阅当前命名空间下指定分组group规则下所有服务的变更事件 * @param serviceNamePattern 服务匹配规则 * @param groupNamePattern 分组group匹配规则 * @param watcher 需要移除的模糊订阅watcher */void cancelFuzzyWatch(String serviceNamePattern, String groupNamePattern, FuzzyWatchEventWatcher watcher);
/** * 订阅当前命名空间下指定分组group规则下所有服务的变更事件 * * @param groupNamePattern 分组匹配规则 * @param watcher 模糊订阅监听器 */void fuzzyWatch(String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
/** * 订阅当前命名空间下指定分组group规则下所有服务的变更事件,可通过Future获取当前匹配的所有服务列表 * * @param groupNamePattern 分组group匹配规则 * @param watcher 模糊订阅监听器 * @return Future 可通过future等待配置异步推送结果 */Future<ListView<String>> fuzzyWatchWithServiceKeys(String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
/** * 取消订阅当前命名空间下指定分组group规则及服务规则下所有配置的服务事件 * * @param groupNamePattern 分组group匹配规则 * @param watcher 需要移除的模糊订阅watcher */void cancelFuzzyWatch(String groupNamePattern, FuzzyWatchEventWatcher watcher) ;请求参数
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| serviceNamePattern | string | 服务名匹配规则,支持a.前缀模糊匹配(如,myservice*) b.后缀模糊匹配(如*service),c.双边模糊匹配(如*service*) |
| groupNamePattern | string | 配置分组匹配规则,支持a.前缀模糊匹配(如 mygroup*) b.后缀模糊匹配(如 *mygroup),c.双边模糊匹配(如 *mygroup*) |
| watcher | FuzzyWatchEventWatcher | 模糊订阅监听器 |
FuzzyWatchEventWatcher模糊订阅监听器
| 方法名 | 方法参数类型 | 描述 |
|---|---|---|
| onEvent | FuzzyWatchChangeEvent | 模糊订阅回调事件对象 |
| getExecutor | void | 可指定执行回调事件的线程池,如果为空,将以nacos推送线程中执行回调 |
FuzzyWatchChangeEvent模糊订阅事件
| 参数名 | 参数类型 | 描述 |
|---|---|---|
| serviceName | string | 变更的服务名 |
| groupName | string | 变更的服务分组group |
| namespace | string | 变更的命名空间 |
| changedType | string | 变更类型,表示客户端接收到的服务变更类型,包含ADD_SERVICE-新增服务,DELETE_SERVICE-移除服务 |
| syncType | string | 触发变更的类型,包含FUZZY_WATCH_INIT_NOTIFY-初始化推送已存在的服务列表,FUZZY_WATCH_DIFF_SYNC_NOTIFY-变更对账触发,FUZZY_WATCH_RESOURCE_CHANGED-服务变更推送 |
返回参数
| 参数类型 | 描述 |
|---|---|
| Future<ListView | 返回当前匹配的服务列表的future对象,当规则匹配的服务列表已经推送到客户端时,可通过future对象获取服务列表 *注意:当触发容量保护时,返回的服务列表可能不全 |
//返回的参数为serviceKey列表,可通过NamingUtils工具类获取serviceName,groupName及namespace String[] serviceKeyItems = NamingUtils.parseServiceKey(serviceKey); String namespace = serviceKeyItems[0]; String groupName = serviceKeyItems[1]; String serviceName = serviceKeyItems[2];服务模糊订阅容量保护机制
处于稳定性角度考虑,避免过多的规则及规则匹配的服务数量导致服务端内存压力以及对客户端造成推送风暴,Nacos在两个层面对模糊订阅功能设计了容量保护机制,当超过上限时,模糊订阅的推送将被抑制。
- 模糊订阅规则数量上限保护 ,默认的模糊订阅规则数量上限为20,可通过参数nacos.naming.fuzzy.watch.max.pattern.count调整上限。
- 单个模糊订阅规则匹配的服务数量上限保护, 默认单个模糊订阅规则匹配的配置数量上限为500,可通过nacos.naming.fuzzy.watch.max.pattern.match.service.count调整上限。
在fuzzyWatch接口中注册模糊订阅监听器可同时实现FuzzyWatchLoadWatcher负载监听器感知容量保护机制的发生。
FuzzyWatchLoadWatcher模糊订阅负载监听器
| 方法名 | 描述 |
|---|---|
| onPatternOverLimit | 当前模糊订阅规则因超过上限,推送被抑制时触发 |
| onServiceReachUpLimit | 当前模糊订阅规则匹配的服务数量达到上限,推送被抑制时触发 |
*注意:
- 当触发容量保护时,通过fuzzyWatchWithServiceKeys返回的服务列表可能不是完整的服务列表。
- 当触发服务数量上限保护时,服务下线的事件也可能因保护机制而导致无法推送。
请求示例
try { // 初始化配置服务,控制台通过示例代码自动获取下面参数 String serverAddr = "{serverAddr}"; String serviceNamePattern = "service*"; String groupPattern = "group*"; Properties properties = new Properties(); properties.setProperty("username", System.getenv("NACOS_USERNAME")); properties.setProperty("password", System.getenv("NACOS_PASSWORD")); properties.put("serverAddr", serverAddr); properties.put("namespace", "mynamespaceId");
Future<ListView<String>> future = namingService.fuzzyWatchWithServiceKeys(serviceNamePattern, groupPattern, new AbstractFuzzyWatchEventWatcher() {@Overridepublic void onEvent(FuzzyWatchChangeEvent event) { System.out.println(event.toString()); }
@Overridepublic void onPatternOverLimit() { System.out.println("pattern service over limit ");
}
@Overridepublic void onServiceReachUpLimit() { System.out.println("pattern service over limit "); } }); } catch (NacosException e) { e.printStackTrace(); }4.15. 获取服务端状态
描述
获取当前服务注册与发现服务端状态。
String getServerStatus();请求参数
无。
返回值
| 参数类型 | 描述 |
|---|---|
| String | 服务端状态。 |
请求示例
NamingService naming = NacosFactory.createNamingService("{serverAddr}");String status = naming.getServerStatus();System.out.println(status);5. 分布式锁API
分布式锁功能目前版本还缺少对应的运维API和监听对应锁的API,将在后续版本中添加支持。
5.1. 获取分布式锁
描述
通过此接口可以尝试获取分布式锁,如果获取失败,则返回false,如果获取成功,则返回true。
Boolean lock(LockInstance instance) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| instance | LockInstance | 分布式锁的锁对象实例 | 无,必填 |
LockInstance对象中包含如下参数:
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| key | String | 分布式锁的唯一key,同一类型的锁若key相同时,则认为期望获取同一把锁 | 无,必填 |
| expiredTime | long | 分布式锁的过期时间,单位为毫秒,0表示取到锁后立刻释放,若设置的值小于0,将使用默认值30000 | 0 |
| params | Map<String,String> | 自定义参数,用于扩展锁的自定义属性 | 无 |
| lockType | String | 分布式锁类型,目前仅支持”NACOS_LOCK” | 无 |
Nacos 目前提供一个默认实现的锁类型,即”NACOS_LOCK”,可通过
new NLock()进行快速创建,后续会支持更多类型的锁。
返回参数
获取锁的结果Boolean,如果获取锁成功,则返回true,否则返回false。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");LockService lockService = NacosLockFactory.createLockService(properties);NLock nLock = new NLock("testLock", 5000L);try { if (lockService.lock(nLock)) { System.out.printf("try to lock `testLock` successfully."); } else { System.out.printf("try to lock `testLock` failed, please retry later."); }} catch (NacosException e) { e.printStackTrace();} finally { System.out.printf("try to unlock `testLock`, result: " + lockService.unLock(nLock));}5.2. 释放分布式锁
描述
通过此接口可以释放获取到的分布式锁,如果释放成功,则返回true,否则返回false。
Boolean unLock(LockInstance instance) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| instance | LockInstance | 分布式锁的锁对象实例 | 无,必填 |
LockInstance对象中包含如下参数:
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| key | String | 分布式锁的唯一key,同一类型的锁若key相同时,则认为期望获取同一把锁 | 无,必填 |
| expiredTime | long | 分布式锁的过期时间,单位为毫秒,0表示取到锁后立刻释放,若设置的值小于0,将使用默认值30000 | 0 |
| params | Map<String,String> | 自定义参数,用于扩展锁的自定义属性 | 无 |
| lockType | String | 分布式锁类型,目前仅支持”NACOS_LOCK” | 无 |
Nacos 目前提供一个默认实现的锁类型,即”NACOS_LOCK”,可通过
new NLock()进行快速创建,后续会支持更多类型的锁。
返回参数
释放锁的结果Boolean,如果获取锁成功,则返回true,否则返回false。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");LockService lockService = NacosLockFactory.createLockService(properties);NLock nLock = new NLock("testLock", 5000L);try { if (lockService.lock(nLock)) { System.out.printf("try to lock `testLock` successfully."); } else { System.out.printf("try to lock `testLock` failed, please retry later."); }} catch (NacosException e) { e.printStackTrace();} finally { System.out.printf("try to unlock `testLock`, result: " + lockService.unLock(nLock));}5.3. 远程尝试获取分布式锁
描述
通过此接口可以直接发起远程加锁请求尝试获取分布式锁,语义与lock一致,获取成功返回true,否则返回false。
Boolean remoteTryLock(LockInstance instance) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| instance | LockInstance | 分布式锁的锁对象实例 | 无,必填 |
返回参数
远程尝试加锁结果Boolean,获取成功返回true,否则返回false。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");LockService lockService = NacosLockFactory.createLockService(properties);NLock nLock = new NLock("testLock", 5000L);try { Boolean lockResult = lockService.remoteTryLock(nLock); System.out.printf("remote try lock result: " + lockResult);} catch (NacosException e) { e.printStackTrace();}5.4. 远程释放分布式锁
描述
通过此接口可以直接发起远程解锁请求释放分布式锁,释放成功返回true,否则返回false。
Boolean remoteReleaseLock(LockInstance instance) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| instance | LockInstance | 分布式锁的锁对象实例 | 无,必填 |
返回参数
远程解锁结果Boolean,释放成功返回true,否则返回false。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");LockService lockService = NacosLockFactory.createLockService(properties);NLock nLock = new NLock("testLock", 5000L);try { Boolean lockResult = lockService.remoteTryLock(nLock); if (lockResult) { System.out.printf("remote try lock success, begin release."); Boolean releaseResult = lockService.remoteReleaseLock(nLock); System.out.printf("remote release result: " + releaseResult); }} catch (NacosException e) { e.printStackTrace();}6. MCP 服务
6.1. 查询MCP 服务
描述
通过此接口可以查询指定的MCP服务详细信息,其中包含了MCP服务的元信息和可调用的Endpoint信息。未指定版本时,查询最新的已发布版本。
McpServerDetailInfo getMcpServer(String mcpName) throws NacosException;
McpServerDetailInfo getMcpServer(String mcpName, String version) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| mcpName | String | MCP服务名称 | 无,必填 |
| version | String | MCP服务版本 | 空,当填入为空时,查询最新的已发布版本 |
返回参数
MCP服务详细信息 McpServerDetailInfo
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { McpServerDetailInfo detailInfo = aiService.mcp().getMcpServer(mcpName, null); System.out.println(JsonUtils.toJson(detailInfo));} catch (Exception e) { e.printStackTrace();}6.2. 发布新版本MCP服务
描述
通过此接口可以发布新的MCP服务版本,若MCP服务为首次发布,则会创建新的MCP服务。
直接上线模式下,MCP 服务及指定版本已存在时,请求保持幂等,不会重复创建或修改已有版本。草稿模式需要使用尚未存在的版本,且同一资源不能已有待处理版本;冲突时先通过管理端查看和处理现有草稿。
3.3 新增 createDraft 重载。省略或设置为 false 时保持原有直接上线行为;设置为 true 时只创建草稿,不会自动提交、审核或上线。需要先完成服务端 3.3 升级及 MCP 生命周期迁移;服务端不支持草稿发布时调用失败,不会改为直接上线。草稿的后续操作见 AI 资源生命周期。
String releaseMcpServer(McpServerBasicInfo serverSpecification, McpToolSpecification toolSpecification) throws NacosException;
String releaseMcpServer(McpServerBasicInfo serverSpecification, McpToolSpecification toolSpecification, McpResourceSpecification resourceSpecification) throws NacosException;
String releaseMcpServer(McpServerBasicInfo serverSpecification, McpToolSpecification toolSpecification, McpEndpointSpec endpointSpecification) throws NacosException;
String releaseMcpServer(McpServerBasicInfo serverSpecification, McpToolSpecification toolSpecification, McpResourceSpecification resourceSpecification, McpEndpointSpec endpointSpecification) throws NacosException;
String releaseMcpServer(McpServerBasicInfo serverSpecification, McpToolSpecification toolSpecification, boolean createDraft) throws NacosException;
String releaseMcpServer(McpServerBasicInfo serverSpecification, McpToolSpecification toolSpecification, McpResourceSpecification resourceSpecification, McpEndpointSpec endpointSpecification, boolean createDraft) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| serverSpecification | McpServerBasicInfo | MCP服务基本信息 | 无,必填 |
| toolSpecification | McpToolSpecification | MCP服务工具信息 | 无,可选 |
| resourceSpecification | McpResourceSpecification | MCP服务资源和资源模板信息 | 无,可选 |
| endpointSpecification | McpEndpointSpec | MCP服务Endpoint信息 | 无,可选 |
| createDraft | boolean | 是否只创建生命周期草稿 | false |
返回参数
MCP服务的ID String。返回 ID 不代表草稿已经上线。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { McpServerBasicInfo serverSpecification = new McpServerBasicInfo(); serverSpecification.setName("example-mcp"); serverSpecification.setProtocol("stdio"); serverSpecification.setLocalServerConfig( Collections.<String, Object>singletonMap("command", "my-mcp-server")); com.alibaba.nacos.api.ai.model.mcp.registry.ServerVersionDetail versionDetail = new com.alibaba.nacos.api.ai.model.mcp.registry.ServerVersionDetail(); versionDetail.setVersion("1.0.0"); serverSpecification.setVersionDetail(versionDetail); String mcpId = aiService.mcp().releaseMcpServer(serverSpecification, null, true); System.out.println(mcpId);} catch (Exception e) { e.printStackTrace();}示例创建 stdio 服务的草稿,将 my-mcp-server 替换为实际启动命令。登记定义不会启动 MCP 服务;客户端使用该定义时才按自身配置启动进程。
6.3. 注册MCP服务的Endpoint
描述
注册MCP服务Endpoint到指定MCP服务版本中。
当注册的MCP服务不存在时,会抛出服务不存在的异常。
void registerMcpServerEndpoint(String mcpName, String address, int port) throws NacosException;
void registerMcpServerEndpoint(String mcpName, String address, int port, String version) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| mcpName | String | MCP服务名称 | 无,必填 |
| address | String | MCP服务Endpoint地址 | 无,必填 |
| port | int | MCP服务Endpoint端口 | 无,必填 |
| version | String | MCP服务版本 | 空,当填入为空时,注册Endpoint到最新版本 |
返回参数
无
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { aiService.mcp().registerMcpServerEndpoint(mcpName, "127.0.0.1", 8848, version);} catch (Exception e) { e.printStackTrace();}6.4. 注销MCP服务的Endpoint
描述
注销MCP服务Endpoint到指定MCP服务版本中。
void deregisterMcpServerEndpoint(String mcpName, String address, int port) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| mcpName | String | MCP服务名称 | 无,必填 |
| address | String | MCP服务Endpoint地址 | 无,必填 |
| port | int | MCP服务Endpoint端口 | 无,必填 |
返回参数
无
请求示例
沿用第 6.3 节注册端点的 aiService:
try { aiService.mcp().deregisterMcpServerEndpoint(mcpName, "127.0.0.1", 8848);} catch (Exception e) { e.printStackTrace();}6.5. 订阅MCP 服务
描述
订阅MCP服务,当MCP服务发布新版本时,会收到通知。
当前版本的订阅是通过轮询查询实现的,可能通知有一定的延迟,可以通过配置
nacosAiMcpServerCacheUpdateInterval参数来调整查询间隔,默认为10000ms。
McpServerDetailInfo subscribeMcpServer(String mcpName, AbstractNacosMcpServerListener mcpServerListener) throws NacosException;
McpServerDetailInfo subscribeMcpServer(String mcpName, String version, AbstractNacosMcpServerListener mcpServerListener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| mcpName | String | MCP服务名称 | 无,必填 |
| version | String | MCP服务版本 | 空,当填入为空时,订阅最新版本 |
| mcpServerListener | AbstractNacosMcpServerListener | MCP服务监听器 | 无,必填 |
返回参数
订阅成功时,返回当前MCP服务详细信息 McpServerDetailInfo.
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { ExampleListener listener = new ExampleListener(i); aiService.mcp().subscribeMcpServer(mcpName, listener);} catch (Exception e) { e.printStackTrace();}private static class ExampleListener extends AbstractNacosMcpServerListener {
private final int id;
private ExampleListener(int id) { this.id = id; }
@Override public void onEvent(NacosMcpServerEvent event) { System.out.printf("---------------mcp server listener %s called start---------------%n", id); System.out.printf("mcp server namespaceId: %s, mcpId: %s, mcpName: %s%n", event.getNamespaceId(), event.getMcpId(), event.getMcpName()); System.out.println("mcp server endpoint: " + JsonUtils.toJson( event.getMcpServerDetailInfo().getBackendEndpoints())); System.out.println( "mcp server tools size: " + event.getMcpServerDetailInfo().getToolSpec().getTools().size()); System.out.println("mcp server version: " + event.getMcpServerDetailInfo().getVersionDetail().getVersion()); System.out.printf("---------------mcp server listener %s called end---------------%n", id); }}6.6. 取消订阅MCP 服务
描述
取消订阅MCP服务。取消订阅时传入的监听器mcpServerListener必须和订阅时一致,否则会导致取消订阅失败。
void unsubscribeMcpServer(String mcpName, AbstractNacosMcpServerListener mcpServerListener) throws NacosException;
void unsubscribeMcpServer(String mcpName, String version, AbstractNacosMcpServerListener mcpServerListener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| mcpName | String | MCP服务名称 | 无,必填 |
| version | String | MCP服务版本 | 空,当填入为空时,取消订阅最新版本 |
| mcpServerListener | AbstractNacosMcpServerListener | MCP服务监听器 | 无,必填 |
返回参数
无
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { ExampleListener listener = new ExampleListener(i); aiService.mcp().subscribeMcpServer(mcpName, listener); aiService.mcp().unsubscribeMcpServer(mcpName, listener);} catch (Exception e) { e.printStackTrace();}7. A2A 注册中心
3.3 保留已发布的 A2A API,通过 aiService.agent() 调用。新应用可使用第 11 章的通用 Agent 能力,并参考 RAD 接入指南。
3.3 SDK 会根据服务端是否支持 RAD 自动适配这些旧接口,无需手动选择。服务端从旧版升级后,如需使用新的行为,请重启应用或重新创建 SDK 实例。连接要求见 SDK 运行指南。
7.1. 查询AgentCard
描述
查询AgentCard。
AgentCardDetailInfo getAgentCard(String agentName) throws NacosException;
AgentCardDetailInfo getAgentCard(String agentName, String version) throws NacosException;
AgentCardDetailInfo getAgentCard(String agentName, String version, String registrationType) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentName | String | Agent名称 | 无,必填 |
| version | String | Agent版本 | 空,当填入为空时,查询最新版本 |
| registrationType | String | 注册方式 | 空,当填入为空时,根据注册时的registrationType自动进行url装填 |
返回参数
查询成功时,返回当前AgentCard详细信息 AgentCardDetailInfo.
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);String agentName = "test";try { AgentCardDetailInfo result = aiService.agent().getAgentCard(agentName); result = aiService.agent().getAgentCard(agentName, "1.0.0"); result = aiService.agent().getAgentCard(agentName, "1.0.0", "URL");} catch (Exception e) { e.printStackTrace();}7.2. 发布新版本AgentCard
描述
发布新版本AgentCard。发布失败时抛出异常。
使用旧 A2A SDK 发布接口时,首个版本直接上线并成为最新版本(latest),即使 setAsLatest=false。后续新版本也会直接上线:setAsLatest=true 时设为最新版本,false 时保留原来的最新版本。重复发布已有版本不会覆盖其内容。
使用 3.3 SDK 连接支持 RAD 的服务端时,SDK 会自动按新的发布流程处理,setAsLatest 的作用与 publishAgent 的 autoSubmit 相同:
- Agent 还没有任何版本时,首个版本自动尝试发布,不受参数值影响。
- 后续新版本或已有草稿,
false保存为草稿,true提交发布。 - 已提交审核、已上线或已下线的版本保持不变。
自动发布会遵循已配置的审核流程,可能需要等待审核。此方法没有返回值,可通过控制台确认版本是否已上线。
void releaseAgentCard(AgentCard agentCard) throws NacosException;
void releaseAgentCard(AgentCard agentCard, String registrationType) throws NacosException;
void releaseAgentCard(AgentCard agentCard, String registrationType, boolean setAsLatest) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentCard | AgentCard | AgentCard信息 | 无,必填 |
| registrationType | String | 可选 URL 或 SERVICE。URL 优先使用定义中的声明地址;SERVICE 优先使用运行端点。 | SERVICE |
| setAsLatest | boolean | 是否设为最新版本;3.3 SDK 连接支持 RAD 的服务端时表示是否自动提交发布。首个版本的特殊行为见上文。 | false |
返回参数
无
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { AgentCard agentCard = new AgentCard(); agentCard.setName("test"); agentCard.setDescription("test for agent card"); agentCard.setUrl("http://localhost:8848"); agentCard.setVersion("1.0.0"); agentCard.setProtocolVersion("0.3.0"); agentCard.setPreferredTransport("JSONRPC"); aiService.agent().releaseAgentCard(agentCard); aiService.agent().releaseAgentCard(agentCard, "SERVICE"); aiService.agent().releaseAgentCard(agentCard, "SERVICE", false);} catch (NacosException e) { e.printStackTrace();}7.3. 注册Agent的Endpoint
描述
注册 Agent 的运行地址。对同一个 Agent 和版本,再次调用会替换本客户端此前注册的地址。单地址接口只保留本次传入的地址;如需同时保留 A、B 两个地址,请使用批量接口一起提交。其他客户端注册的地址不受影响。
void registerAgentEndpoint(String agentName, String version, String address, int port) throws NacosException;
void registerAgentEndpoint(String agentName, String version, String address, int port, String transport) throws NacosException;
void registerAgentEndpoint(String agentName, String version, String address, int port, String transport, String path) throws NacosException;
void registerAgentEndpoint(String agentName, String version, String address, int port, String transport, String path, boolean supportTls) throws NacosException;
void registerAgentEndpoint(String agentName, AgentEndpoint endpoint) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentName | String | Agent名称 | 无,必填 |
| version | String | Agent版本 | 无,必填 |
| address | String | Agent的IP地址 | 无,必填 |
| port | int | Agent的端口号 | 无,必填 |
| transport | String | 该endpoint的传输方式JSONRPC, GRPC, HTTP+JSON | JSONRPC |
| path | String | 该endpoint的访问路径 | 空字符串 |
| supportTls | boolean | 是否支持TLS | false |
| endpoint | AgentEndpoint | AgentEndpoint | 无,必填 |
返回参数
无
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { aiService.agent().registerAgentEndpoint("test", "1.0.0", "127.0.0.1", 8848); aiService.agent().registerAgentEndpoint("test", "1.0.0", "127.0.0.1", 8848, "JSONRPC"); aiService.agent().registerAgentEndpoint("test", "1.0.0", "127.0.0.1", 8848, "JSONRPC", ""); aiService.agent().registerAgentEndpoint("test", "1.0.0", "127.0.0.1", 8848, "JSONRPC", "", false); AgentEndpoint endpoint = new AgentEndpoint(); endpoint.setAddress("127.0.0.1"); endpoint.setPort(8848); endpoint.setTransport("JSONRPC"); endpoint.setPath(""); endpoint.setSupportTls(false); endpoint.setVersion("1.0.0"); aiService.agent().registerAgentEndpoint("test", endpoint);} catch (NacosException e) { e.printStackTrace();}7.4. 注销Agent的Endpoint
描述
从AgentCard中注销Endpoint。
使用 3.3 SDK 连接支持 RAD 的服务端时,即使只传入一个地址,也会注销本客户端为该版本注册的全部地址,其他版本的地址保留。如果需要只移除指定地址,请配套使用第 11.5、11.6 节的新注册和注销接口。
void deregisterAgentEndpoint(String agentName, String version, String address, int port) throws NacosException;
void deregisterAgentEndpoint(String agentName, AgentEndpoint endpoint) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentName | String | Agent名称 | 无,必填 |
| version | String | Agent版本 | 无,必填 |
| address | String | Agent的IP地址 | 无,必填 |
| port | int | Agent的端口号 | 无,必填 |
| endpoint | AgentEndpoint | AgentEndpoint | 无,必填 |
返回参数
无
请求示例
沿用第 7.3 节注册端点的 aiService:
try { aiService.agent().deregisterAgentEndpoint("test", "1.0.0", "127.0.0.1", 8848); AgentEndpoint endpoint = new AgentEndpoint(); endpoint.setAddress("127.0.0.1"); endpoint.setPort(8848); endpoint.setVersion("1.0.0"); aiService.agent().deregisterAgentEndpoint("test", endpoint);} catch (NacosException e) { e.printStackTrace();}7.5. 订阅AgentCard
描述
订阅AgentCard,当AgentCard发布新版本时,会收到通知。
连接旧版服务端时,SDK 定期查询 AgentCard,间隔由
nacosAiAgentCardCacheUpdateInterval设置,默认 10000ms。3.3 SDK 连接支持 RAD 的服务端时,会自动使用新的订阅方式,该参数不再控制通知间隔。
使用旧 subscribeAgentCard 接口订阅时,如果 AgentCard 被删除或暂时查不到,SDK 默认会触发保护:不会向监听器传入 null 或空 Card,也不会发送删除通知。
AgentCardDetailInfo subscribeAgentCard(String agentName, AbstractNacosAgentCardListener agentCardListener) throws NacosException;
AgentCardDetailInfo subscribeAgentCard(String agentName, String version, AbstractNacosAgentCardListener agentCardListener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentName | String | Agent名称 | 无,必填 |
| version | String | Agent版本 | 当为空时,订阅最新版本 |
| agentCardListener | AbstractNacosAgentCardListener | 监听器 | 无,必填 |
返回参数
订阅成功时,返回当前AgentCard详细信息 AgentCardDetailInfo.
请求示例
import com.alibaba.nacos.api.ai.AiFactory;import com.alibaba.nacos.api.ai.AiService;import com.alibaba.nacos.api.ai.listener.AbstractNacosAgentCardListener;import com.alibaba.nacos.api.ai.listener.NacosAgentCardEvent;import com.alibaba.nacos.api.ai.model.a2a.AgentCardDetailInfo;import java.util.Properties;
Properties properties = new Properties();properties.setProperty("serverAddr", "{serverAddr}");properties.setProperty("namespace", "{namespaceId}");properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));AbstractNacosAgentCardListener listener = new AbstractNacosAgentCardListener() { @Override public void onEvent(NacosAgentCardEvent event) { System.out.println("Card changed: " + event.getAgentCard().getVersion()); }};AiService aiService = AiFactory.createAiService(properties);try { AgentCardDetailInfo initial = aiService.agent().subscribeAgentCard("test", "1.0.0", listener); try { System.out.println("Press Enter to unsubscribe."); System.in.read(); } finally { aiService.agent().unsubscribeAgentCard("test", "1.0.0", listener); }} finally { aiService.shutdown();}7.6. 取消订阅AgentCard
取消订阅 AgentCard。取消订阅时传入的监听器agentCardListener必须和订阅时一致,否则会导致取消订阅失败。
描述
void unsubscribeAgentCard(String agentName, AbstractNacosAgentCardListener agentCardListener) throws NacosException;
void unsubscribeAgentCard(String agentName, String version, AbstractNacosAgentCardListener agentCardListener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentName | String | Agent名称 | 无,必填 |
| version | String | Agent版本 | 当为空时,取消订阅最新版本 |
| agentCardListener | AbstractNacosAgentCardListener | 监听器 | 无,必填 |
返回参数
无
请求示例
// Use the same live aiService and listener as the subscription in section 7.5.aiService.agent().unsubscribeAgentCard("test", "1.0.0", listener);7.7. 批量注册Agent的Endpoint
批量注册本客户端为同一 Agent、同一版本保留的全部地址。例如,原来注册了 A、B,现在需要 B、C,直接提交 B、C 即可;需要保留的地址必须一起提交。其他客户端或其他协议注册的地址不受影响。
该 API 从 3.1.1 开始提供。
描述
void registerAgentEndpoint(String agentName, Collection<AgentEndpoint> endpoints) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentName | String | Agent名称 | 无,必填 |
| endpoints | Collection | Agent Endpoint 集合 | 无,必填 |
注意:endpoints中的所有AgentEndpoint的version应该不为空且相同。
返回参数
无
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { AgentEndpoint endpoint1 = new AgentEndpoint(); endpoint1.setAddress("127.0.0.1"); endpoint1.setPort(8848); endpoint1.setTransport("JSONRPC"); endpoint1.setPath(""); endpoint1.setSupportTls(false); endpoint1.setVersion("1.0.0");
AgentEndpoint endpoint2 = new AgentEndpoint(); endpoint2.setAddress("127.0.0.1"); endpoint2.setPort(8849); endpoint2.setTransport("JSONRPC"); endpoint2.setPath(""); endpoint2.setSupportTls(false); endpoint2.setVersion("1.0.0");
aiService.agent().registerAgentEndpoint("test", Arrays.asList(endpoint1, endpoint2));} catch (NacosException e) { e.printStackTrace();}8. Skill 能力
Skill 在 Java SDK 中以 ZIP 压缩包的形式分发,包含 SKILL.md 和全部资源文件(二进制资源会从 Base64 自动解码为原始字节)。SDK 当前提供按名称、按版本、按标签三种下载方式,并支持订阅 Skill 变更。
8.1. 下载 Skill ZIP
描述
根据 Skill 名称下载最新版本的 Skill ZIP 压缩包(字节数组)。
byte[] downloadSkillZip(String skillName) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| skillName | String | Skill 名称(唯一标识) | 无,必填 |
返回参数
Skill ZIP 压缩包字节数组 byte[],包含 SKILL.md 与全部资源文件。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { byte[] skillZip = aiService.skill().downloadSkillZip("{skillName}"); System.out.println("skill zip bytes: " + skillZip.length);} catch (NacosException e) { e.printStackTrace();}异常说明
Skill 不存在或查询异常时,抛出 NacosException。
8.2. 按版本下载 Skill ZIP
描述
根据 Skill 名称和目标版本下载对应版本的 Skill ZIP 压缩包(字节数组)。
byte[] downloadSkillZipByVersion(String skillName, String version) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| skillName | String | Skill 名称(唯一标识) | 无,必填 |
| version | String | 目标 Skill 版本,为 null 时获取最新版本 | 无 |
返回参数
Skill ZIP 压缩包字节数组 byte[]。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { byte[] skillZip = aiService.skill().downloadSkillZipByVersion("{skillName}", "1.0.0"); System.out.println("skill zip bytes: " + skillZip.length);} catch (NacosException e) { e.printStackTrace();}异常说明
Skill 或指定版本不存在、查询异常时,抛出 NacosException。
8.3. 按标签下载 Skill ZIP
描述
根据 Skill 名称和标签下载对应标签的 Skill ZIP 压缩包(字节数组)。
byte[] downloadSkillZipByLabel(String skillName, String label) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| skillName | String | Skill 名称(唯一标识) | 无,必填 |
| label | String | 目标标签(例如:latest、stable) | 无,必填 |
返回参数
Skill ZIP 压缩包字节数组 byte[]。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { byte[] skillZip = aiService.skill().downloadSkillZipByLabel("{skillName}", "{label}"); System.out.println("skill zip bytes: " + skillZip.length);} catch (NacosException e) { e.printStackTrace();}异常说明
Skill 或指定标签不存在、查询异常时,抛出 NacosException。
8.4. 订阅 Skill
描述
订阅 Skill 变更,当 Skill ZIP 内容变化时通过监听器回调。version、label 可选,用于限定订阅范围。
byte[] subscribeSkill(String skillName, String version, String label, AbstractNacosSkillListener skillListener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| skillName | String | Skill 名称 | 无,必填 |
| version | String | 目标 Skill 版本,可选 | 无 |
| label | String | 目标标签,可选 | 无 |
| skillListener | AbstractNacosSkillListener | Skill 变更回调监听器 | 无,必填 |
返回参数
订阅成功时返回当前 Skill ZIP 压缩包字节数组 byte[],未找到时可为 null。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { byte[] skillZip = aiService.skill().subscribeSkill("{skillName}", null, "{label}", new AbstractNacosSkillListener() { @Override public void onEvent(NacosSkillEvent event) { System.out.println("skill changed: " + event.getSkillName()); System.out.println("resolved version: " + event.getResolvedVersion()); System.out.println("md5: " + event.getMd5()); } }); System.out.println("skill zip bytes: " + (skillZip != null ? skillZip.length : 0));} catch (NacosException e) { e.printStackTrace();}异常说明
请求参数不合法或订阅处理异常时,抛出 NacosException。
8.5. 取消订阅 Skill
描述
取消对 Skill 的订阅。取消时传入的 skillName、version、label、listener 需与订阅时一致。
void unsubscribeSkill(String skillName, String version, String label, AbstractNacosSkillListener skillListener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| skillName | String | Skill 名称 | 无,必填 |
| version | String | 目标版本,可选 | 无 |
| label | String | 目标标签,可选 | 无 |
| skillListener | AbstractNacosSkillListener | 订阅时使用的监听器 | 无,必填 |
返回参数
无
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);AbstractNacosSkillListener listener = new AbstractNacosSkillListener() {};try { aiService.skill().subscribeSkill("{skillName}", null, "{label}", listener); aiService.skill().unsubscribeSkill("{skillName}", null, "{label}", listener);} catch (NacosException e) { e.printStackTrace();}异常说明
请求参数不合法或取消订阅处理异常时,抛出 NacosException。
9. Prompt 能力
9.1. 获取 Prompt
描述
根据 Prompt 的 key 获取当前版本的 Prompt 对象。
Prompt getPrompt(String promptKey) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| promptKey | String | Prompt 的 key(唯一标识) | 无,必填 |
返回参数
| 参数类型 | 描述 |
|---|---|
| Prompt | 当前版本的 Prompt 对象 |
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { Prompt prompt = aiService.prompt().getPrompt("{promptKey}"); System.out.println(JsonUtils.toJson(prompt));} catch (NacosException e) { e.printStackTrace();}异常说明
Prompt 不存在或查询异常时,抛出 NacosException。
9.2. 按版本获取 Prompt
描述
根据 Prompt 的 key 和指定版本获取 Prompt 对象。version 为 null 时返回最新版本。
Prompt getPromptByVersion(String promptKey, String version) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| promptKey | String | Prompt 的 key(唯一标识) | 无,必填 |
| version | String | 目标版本,null 表示最新版本 | 无 |
返回参数
| 参数类型 | 描述 |
|---|---|
| Prompt | 指定版本的 Prompt 对象 |
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { Prompt prompt = aiService.prompt().getPromptByVersion("{promptKey}", "1.0.0"); System.out.println(JsonUtils.toJson(prompt));} catch (NacosException e) { e.printStackTrace();}9.3. 按标签获取 Prompt
描述
根据 Prompt 的 key 和标签获取对应版本的 Prompt 对象。
Prompt getPromptByLabel(String promptKey, String label) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| promptKey | String | Prompt 的 key(唯一标识) | 无,必填 |
| label | String | 目标标签 | 无,必填 |
返回参数
| 参数类型 | 描述 |
|---|---|
| Prompt | 该标签对应的 Prompt 对象 |
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { Prompt prompt = aiService.prompt().getPromptByLabel("{promptKey}", "{label}"); System.out.println(JsonUtils.toJson(prompt));} catch (NacosException e) { e.printStackTrace();}9.4. 订阅 Prompt
描述
订阅 Prompt 变更,当 Prompt 配置变化时通过监听器回调。version、label 可选,用于限定订阅范围。
Prompt subscribePrompt(String promptKey, String version, String label, AbstractNacosPromptListener promptListener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| promptKey | String | Prompt 的 key | 无,必填 |
| version | String | 目标版本,可选 | 无 |
| label | String | 目标标签,可选 | 无 |
| promptListener | AbstractNacosPromptListener | Prompt 变更回调监听器 | 无,必填 |
返回参数
| 参数类型 | 描述 |
|---|---|
| Prompt | 订阅成功时返回当前 Prompt,未找到可为 null |
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { Prompt prompt = aiService.prompt().subscribePrompt("{promptKey}", null, null, new AbstractNacosPromptListener() { @Override public void onEvent(NacosPromptEvent event) { System.out.println("prompt changed: " + event.getPromptKey()); } }); System.out.println(JsonUtils.toJson(prompt));} catch (NacosException e) { e.printStackTrace();}9.5. 取消订阅 Prompt
描述
取消对 Prompt 的订阅。取消时传入的 version、label、listener 需与订阅时一致。
void unsubscribePrompt(String promptKey, String version, String label, AbstractNacosPromptListener promptListener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| promptKey | String | Prompt 的 key | 无,必填 |
| version | String | 目标版本,可选 | 无 |
| label | String | 目标标签,可选 | 无 |
| promptListener | AbstractNacosPromptListener | 订阅时使用的监听器 | 无,必填 |
返回参数
无
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);AbstractNacosPromptListener listener = new AbstractNacosPromptListener() {};try { aiService.prompt().subscribePrompt("{promptKey}", null, null, listener); aiService.prompt().unsubscribePrompt("{promptKey}", null, null, listener);} catch (NacosException e) { e.printStackTrace();}10. AgentSpec 能力
10.1. 查询 AgentSpec
描述
根据 AgentSpec 名称查询完整的 AgentSpec 对象,包含主配置及全部资源配置。
AgentSpec loadAgentSpec(String agentSpecName) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentSpecName | String | AgentSpec 名称(唯一标识) | 无,必填 |
返回参数
查询成功时,返回 AgentSpec 对象 AgentSpec.
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { AgentSpec agentSpec = aiService.agentSpec().loadAgentSpec("{agentSpecName}"); System.out.println(JsonUtils.toJson(agentSpec));} catch (NacosException e) { e.printStackTrace();}10.2. 订阅 AgentSpec
描述
订阅指定 AgentSpec,当 AgentSpec 配置发生变更时通过监听器回调。
AgentSpec subscribeAgentSpec(String agentSpecName, AbstractNacosAgentSpecListener agentSpecListener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentSpecName | String | AgentSpec 名称 | 无,必填 |
| agentSpecListener | AbstractNacosAgentSpecListener | AgentSpec 变更回调监听器 | 无,必填 |
返回参数
订阅成功时,返回当前 AgentSpec 对象 AgentSpec,未找到时可为 null。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);try { AgentSpec agentSpec = aiService.agentSpec().subscribeAgentSpec("{agentSpecName}", new AbstractNacosAgentSpecListener() { @Override public void onEvent(NacosAgentSpecEvent event) { System.out.println("agent spec changed: " + event.getAgentSpecName()); } }); System.out.println(JsonUtils.toJson(agentSpec));} catch (NacosException e) { e.printStackTrace();}10.3. 取消订阅 AgentSpec
描述
取消对指定 AgentSpec 的订阅。取消时传入的监听器必须与订阅时一致,否则可能导致取消失败。
void unsubscribeAgentSpec(String agentSpecName, AbstractNacosAgentSpecListener agentSpecListener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentSpecName | String | AgentSpec 名称 | 无,必填 |
| agentSpecListener | AbstractNacosAgentSpecListener | 订阅时使用的监听器 | 无,必填 |
返回参数
无
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");AiService aiService = AiFactory.createAiService(properties);AbstractNacosAgentSpecListener listener = new AbstractNacosAgentSpecListener() {};try { aiService.agentSpec().subscribeAgentSpec("{agentSpecName}", listener); aiService.agentSpec().unsubscribeAgentSpec("{agentSpecName}", listener);} catch (NacosException e) { e.printStackTrace();}11. Agent 管理与发现
Agent 管理与发现 API 通过 aiService.agent() 获取,覆盖目录搜索、定义发现、订阅、定义发布以及运行时 Endpoint 注册。第 7 章的旧 A2A API 保留兼容;新接入优先使用本章的通用能力,完整示例见 RAD 接入指南。
以下接口从 3.3.0 开始提供,使用创建 AiService 时配置的命名空间,无需在每个请求中重复设置。模型类位于 com.alibaba.nacos.api.ai.model.agent 包,发布请求位于其 client 子包。
需要兼容旧版服务端时,可以用 AiService.getAgentDiscoveryCapability() 查询是否支持 RAD。返回 UNKNOWN 表示暂时无法判断,查询失败也可能抛出 NacosException。普通应用可直接使用本章接口;框架适配示例见 RAD 接入指南。
需要将发现结果转为 A2A AgentCard 时,可使用 AgentService.a2aConverter() 或 AgentConverters.a2a()。用法及错误处理见 查询结果转为 A2A AgentCard。
11.1. 搜索 Agent
描述
搜索当前 Namespace 中可见、已启用且至少存在一个在线版本的 Agent。agentNameContains 执行大小写敏感的字面量子串匹配,tagsAll 中的值按 AND 匹配,protocolsAny 中的值按 OR 匹配。
Page<AgentSummary> searchAgents(AgentSearchRequest request) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| request | AgentSearchRequest | Agent 搜索条件 | 无,必填 |
AgentSearchRequest 包含以下字段:
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentNameContains | String | Agent 名称中大小写敏感的字面量子串 | 无 |
| tagsAll | List<String> | Agent 必须同时包含的全部标签 | 无 |
| protocolsAny | List<String> | 任一在线版本需要暴露的任一调用协议 | 无 |
| pageNo | Integer | 从 1 开始的页码 | 1 |
| pageSize | Integer | 每页数量,取值范围为 1~100 | 20 |
返回参数
返回 Page<AgentSummary>,包含总数、当前页码、总页数和 Agent 目录条目。在线版本在 versionInfo.onlineVersions 中,默认版本通过 versionInfo.labels.latest 读取;不包含完整协议定义或 Endpoint。刚发布后的搜索结果可能短暂不完整,搜索命中也不保证存在健康端点。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");properties.setProperty(PropertyKeyConst.NAMESPACE, "{namespaceId}");AiService aiService = AiFactory.createAiService(properties);
AgentSearchRequest request = new AgentSearchRequest();request.setAgentNameContains("order");request.setTagsAll(Arrays.asList("production", "public"));request.setProtocolsAny(Collections.singletonList("a2a"));request.setPageNo(1);request.setPageSize(20);
Page<AgentSummary> page = aiService.agent().searchAgents(request);System.out.println(JsonUtils.toJson(page));异常说明
请求为空、页码或每页数量越界,或远程请求失败时,抛出 NacosException。
11.2. 发现 Agent
描述
根据 Agent 名称以及可选的精确版本或标签,获取一个完整的 Agent 发现快照。可通过 Filter 裁剪调用协议和 Endpoint 集合。Filter 只裁剪当前结果,不会选择另一个 Agent 版本,也不执行负载均衡。
AgentDiscoveryResult discoverAgent(AgentReference reference) throws NacosException;
AgentDiscoveryResult discoverAgent(AgentReference reference, AgentDiscoveryFilter filter) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| reference | AgentReference | Agent 引用 | 无,必填 |
| filter | AgentDiscoveryFilter | 可选的协议、传输、Endpoint 来源和元数据过滤条件 | 无 |
AgentReference 包含以下字段:
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentName | String | Agent 名称 | 无,必填 |
| version | String | 精确在线版本,与 label 互斥 | 无 |
| label | String | 请求时解析到在线版本的标签,与 version 互斥 | 无 |
AgentDiscoveryFilter 的所有字段均为可选:
| 名称 | 类型 | 描述 |
|---|---|---|
| protocols | List<String> | 允许的调用协议,列表内按 OR 匹配 |
| protocolVersion | String | 与候选调用接口的协议版本精确匹配 |
| transports | List<String> | 允许的传输类型,列表内按 OR 匹配 |
| endpointSources | List<EndpointSource> | 允许的 RUNTIME 或 DECLARED 来源 |
| metadataSelector | Map<String, String> | Endpoint Metadata 必须同时包含的精确键值 |
返回参数
返回 AgentDiscoveryResult,包含 Agent 名称、解析后的精确版本、contentDigest 和 callInterfaces。地址位于各接口的 endpointSets[].endpoints[];接口或地址集合可能为空,也可能包含 healthy=false 的运行端点。应用按协议、来源、健康状态、priority 和 weight 选择地址,再调用 Agent 服务。
version 和 label 均留空时,定义元数据使用当前 latest,运行时 Endpoint 则可匹配任一当前在线版本。显式设置 label=latest 时,定义和运行时 Endpoint 都严格限定为当前 latest。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");properties.setProperty(PropertyKeyConst.NAMESPACE, "{namespaceId}");AiService aiService = AiFactory.createAiService(properties);
AgentReference reference = new AgentReference();reference.setAgentName("{agentName}");
AgentDiscoveryFilter filter = new AgentDiscoveryFilter();filter.setProtocols(Collections.singletonList("a2a"));filter.setEndpointSources(Arrays.asList(EndpointSource.RUNTIME, EndpointSource.DECLARED));
AgentDiscoveryResult result = aiService.agent().discoverAgent(reference, filter);System.out.println(JsonUtils.toJson(result));异常说明
Agent 引用无效、version 与 label 同时设置、Filter 无效、Agent 或目标版本不存在,或远程请求失败时,抛出 NacosException。
11.3. 订阅 Agent
描述
订阅 Agent 定义和地址的变化,方法没有返回值。初始状态和后续变化都通过监听器的 onEvent 接收;目标尚不存在时收到 UNAVAILABLE 事件,SDK 保留订阅并等待目标可用。首次回调可能在方法返回前或返回后发生,请在调用前准备好监听器使用的数据,并仅通过回调更新本地状态。相同查询条件下重复添加同一个监听器不会重复初始化;新监听器会收到当前状态。
SNAPSHOT:包含完整查询结果,用它替换本地保存的结果。地址列表可能为空,也可能包含不健康地址,需要检查后再使用。UNAVAILABLE:SDK 查询确认 Agent、指定版本或标签不存在。此时停止使用旧结果;目标恢复后会继续通知。
订阅期间遇到网络、权限或订阅数量限制等错误时,SDK 会保留订阅并自动重试,无需重复订阅。查看客户端日志可了解错误原因。回调较慢时可能跳过中间状态,优先通知最新结果。
方法签名
void subscribeAgent(AgentReference reference, AbstractNacosAgentDiscoveryListener listener) throws NacosException;
void subscribeAgent(AgentReference reference, AgentDiscoveryFilter filter, AbstractNacosAgentDiscoveryListener listener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| reference | AgentReference | 与发现请求相同的 Agent 引用 | 无,必填 |
| filter | AgentDiscoveryFilter | 与发现请求相同的可选 Filter | 无 |
| listener | AbstractNacosAgentDiscoveryListener | 接收完整替换快照的监听器 | 无,必填 |
返回参数
| 参数类型 | 描述 |
|---|---|
| void | 初始状态和后续变化通过监听器接收。 |
请求示例
import com.alibaba.nacos.api.ai.listener.AbstractNacosAgentDiscoveryListener;import com.alibaba.nacos.api.ai.listener.NacosAgentDiscoveryEvent;import com.alibaba.nacos.api.ai.model.agent.AgentDiscoveryResult;import com.alibaba.nacos.api.ai.model.agent.AgentReference;import java.util.concurrent.atomic.AtomicReference;
// Reuse an AiService created with the connection and authentication properties above.AgentReference reference = new AgentReference();reference.setAgentName("{agentName}");AtomicReference<NacosAgentDiscoveryEvent> current = new AtomicReference<>();AbstractNacosAgentDiscoveryListener listener = new AbstractNacosAgentDiscoveryListener() { @Override public void onEvent(NacosAgentDiscoveryEvent event) { current.set(event); }};try { aiService.agent().subscribeAgent(reference, listener); try { System.in.read(); } finally { aiService.agent().unsubscribeAgent(reference, listener); }} finally { aiService.shutdown();}异常说明
调用时如果参数无效、首次查询发生非目标不存在类错误或订阅数量超限,可能抛出 NacosException。这表示本次订阅未成功,需要处理原因后重新调用。目标尚不存在时通过监听器通知 UNAVAILABLE,无需重复订阅。
11.4. 取消订阅 Agent
描述
取消当前客户端的 Agent 订阅。传入与订阅时相同的查询条件和同一个监听器实例。取消订阅不会注销运行地址或停止 Agent 服务。
void unsubscribeAgent(AgentReference reference, AbstractNacosAgentDiscoveryListener listener) throws NacosException;
void unsubscribeAgent(AgentReference reference, AgentDiscoveryFilter filter, AbstractNacosAgentDiscoveryListener listener) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| reference | AgentReference | 订阅时使用的 Agent 引用 | 无,必填 |
| filter | AgentDiscoveryFilter | 订阅时使用的 Filter;未过滤订阅传 null | 无 |
| listener | AbstractNacosAgentDiscoveryListener | 订阅时使用的同一监听器实例 | 无,必填 |
返回参数
无。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");properties.setProperty(PropertyKeyConst.NAMESPACE, "{namespaceId}");AiService aiService = AiFactory.createAiService(properties);
AgentReference reference = new AgentReference();reference.setAgentName("{agentName}");AbstractNacosAgentDiscoveryListener listener = new AbstractNacosAgentDiscoveryListener() { @Override public void onEvent(NacosAgentDiscoveryEvent event) { if (event.getType() == NacosAgentDiscoveryEventType.SNAPSHOT) { System.out.println(JsonUtils.toJson(event.getAgentDiscoveryResult())); } else { System.err.println(event.getErrorCode() + ": " + event.getErrorMessage()); } }};try { aiService.agent().subscribeAgent(reference, listener); aiService.agent().unsubscribeAgent(reference, listener);} finally { aiService.shutdown();}异常说明
引用、Filter 或监听器无效时,抛出 NacosException。
11.5. 注册 Agent 运行时 Endpoint
描述
注册本客户端为同一 Agent、同一种协议保留的全部运行地址。再次调用会替换此前的地址列表,即使本次版本号不同。例如,原来注册了 A、B,现在需要 B、C,应提交 B、C。其他客户端和其他协议注册的地址不受影响。注册地址不会创建 Agent 定义。
void registerAgentEndpoints(AgentEndpointRegistrationBatch batch) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| batch | AgentEndpointRegistrationBatch | 本次要保留的全部运行地址及版本信息 | 无,必填 |
AgentEndpointRegistrationBatch 包含以下字段:
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentName | String | Agent 名称 | 无,必填 |
| runtimeVersion | String | Endpoint 未覆盖时使用的运行版本;每个 Endpoint 必须能取得生效版本 | 无 |
| versionRange | String | Endpoint 未覆盖时使用的兼容范围,必须包含生效运行版本 | 两层均未提供时为精确运行版本范围 |
| protocol | String | 调用协议,如 a2a | 无,必填 |
| endpoints | List<Endpoint> | 本客户端要保留的全部运行地址,数量为 1~1000 | 无,必填 |
Endpoint 包含以下字段:
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| uri | String | 完整绝对调用 URI | 无,必填 |
| transport | String | 规范传输类型,如 HTTP+JSON | 无,必填 |
| priority | Integer | 优先级,数值越小越优先 | 0 |
| weight | Double | 同一优先级内的权重 | 1 |
| metadata | Map<String, String> | 扁平 Endpoint 元数据 | 无 |
每个地址还可设置 healthy 和 enabled(默认均为 true,不能为 null)。未设置 bindings 时,使用本次注册请求中的版本和兼容范围;需要单独指定时,在 bindings 中填写一条 RuntimeVersionBinding。兼容范围必须包含运行版本。查询结果不包含已禁用的地址,但可能包含不健康地址。
端点按 URI 主机、有效端口和 transport 区分,仅 path 或 query 不同不能作为同一发布者的两个独立端点。正常退出时注销端点并关闭 AiService;完整运行流程见 RAD 接入指南。
返回参数
无。
请求示例
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");properties.setProperty(PropertyKeyConst.NAMESPACE, "{namespaceId}");AiService aiService = AiFactory.createAiService(properties);
Endpoint endpoint = new Endpoint();endpoint.setUri("https://agent.example.com:443/a2a");endpoint.setTransport("HTTP+JSON");endpoint.setPriority(0);endpoint.setWeight(1.0D);
AgentEndpointRegistrationBatch batch = new AgentEndpointRegistrationBatch();batch.setAgentName("{agentName}");batch.setRuntimeVersion("1.1.0");batch.setVersionRange("[1.0.0,2.0.0)");batch.setProtocol("a2a");batch.setEndpoints(Collections.singletonList(endpoint));
aiService.agent().registerAgentEndpoints(batch);异常说明
注册参数无效、兼容范围不包含运行版本,或注册失败时,抛出 NacosException。
11.6. 注销 Agent 运行时 Endpoint
描述
移除本客户端注册的指定运行地址,其余地址保留。匹配地址时,使用 URI 的主机、有效端口和 transport。
void deregisterAgentEndpoints(String agentName, String protocol, List<Endpoint> endpoints) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentName | String | Agent 名称 | 必填 |
| protocol | String | 调用协议 | 必填 |
| endpoints | List<Endpoint> | 要移除的端点 | 非空列表 |
命名空间由 SDK 提供。列表中的 Endpoint 只需填写 uri 和 transport,应使用实际注册过的地址,并复用注册时的同一个 aiService 实例。
返回参数
无。
请求示例
沿用第 11.5 节注册端点的 aiService:
Endpoint endpoint = new Endpoint();endpoint.setUri("https://agent.example.com:443/a2a");endpoint.setTransport("HTTP+JSON");
aiService.agent().deregisterAgentEndpoints("{agentName}", "a2a", Collections.singletonList(endpoint));异常说明
Agent 名称、协议或端点标识无效,或注销请求失败时,抛出 NacosException。
11.7. 代码式发布 Agent 定义
描述
从应用代码中发布指定版本的 Agent 定义,使用 AiService 配置的命名空间。
| 情况 | autoSubmit=false | autoSubmit=true |
|---|---|---|
| Agent 还没有任何版本,创建首个版本 | 自动尝试发布 | 自动尝试发布 |
| 创建后续版本,或更新已有草稿 | 保存为草稿 | 提交发布 |
| 该版本已提交审核、已上线或已下线 | 返回已有版本,不修改 | 返回已有版本,不修改 |
已有草稿也算已有版本。更新草稿会替换整个定义,包括全部调用接口,需要保留的内容应一起提交。
自动发布会遵循已配置的审核流程,可能需要等待审核。检查返回的 AgentVersionDetail.getStatus() 是否为 online,确认版本已上线。若调用失败或超时,先检查版本是否已保存,再决定是否重试。
本节使用的
AgentProvider和AgentVersionDetail位于com.alibaba.nacos.api.ai.model.agent包,不是旧 A2A 的com.alibaba.nacos.api.ai.model.a2a同名类型。
AgentVersionDetail publishAgent(AgentPublishRequest request) throws NacosException;请求参数
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| request | AgentPublishRequest | Agent 定义发布请求 | 无,必填 |
com.alibaba.nacos.api.ai.model.agent.client.AgentPublishRequest 与管理端草稿请求共享定义字段,并增加 autoSubmit:
| 名称 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| agentName | String | Agent 名称 | 无,必填 |
| displayName | String | 首次创建 Agent 时的可选展示名称 | 无 |
| description | String | 首次创建 Agent 时的可选目录描述 | 无 |
| iconUrl | String | 首次创建 Agent 时的可选图标 URI | 无 |
| provider | AgentProvider | 首次创建 Agent 时的可选提供方 name 和 url | 无 |
| tags | List<String> | 首次创建 Agent 时的可选公开目录标签 | 无 |
| extensions | Map<String, Object> | 首次创建 Agent 时的可选公开扩展 | 无 |
| version | String | 要创建的精确 SemVer 版本 | 无,必填 |
| callInterfaces | List<AgentCallInterface> | 非空的有序协议定义;与 basedOnVersion 必须且只能填写其中一项 | 条件必填 |
| basedOnVersion | String | 复用内容的精确源版本;与 callInterfaces 二选一 | 条件必填 |
| author | String | Version 作者 | 无 |
| changeDescription | String | Version 变更说明 | 无 |
| autoSubmit | boolean | 是否自动提交发布;首个版本总会尝试发布,详见上表 | false |
AgentCallInterface 包含协议、协议版本、descriptorMediaType、原生 nativeDescriptor、endpointSourceOrder 及 endpointSets。来源顺序必须恰好包含 RUNTIME 和 DECLARED 各一次;定义中的声明地址放入 source=DECLARED 的 EndpointSet,不写入运行端点。同一版本中 protocol 不能重复。
首次创建 Agent 时必须直接提供 callInterfaces,因为尚不存在可复用的源版本,不能使用 basedOnVersion。创建后续版本时仍必须在直接内容和一个精确源版本之间二选一。
返回参数
返回精确的 AgentVersionDetail,包含 Namespace、Agent 名称、版本、当前状态、调用接口、作者、变更说明、contentDigest 和审计时间。
请求示例
import com.alibaba.nacos.api.PropertyKeyConst;import com.alibaba.nacos.api.ai.AiFactory;import com.alibaba.nacos.api.ai.AiService;import com.alibaba.nacos.api.ai.model.a2a.AgentCapabilities;import com.alibaba.nacos.api.ai.model.a2a.AgentCard;import com.alibaba.nacos.api.ai.model.a2a.AgentInterface;import com.alibaba.nacos.api.ai.model.agent.AgentCallInterface;import com.alibaba.nacos.api.ai.model.agent.AgentVersionDetail;import com.alibaba.nacos.api.ai.model.agent.Endpoint;import com.alibaba.nacos.api.ai.model.agent.EndpointSet;import com.alibaba.nacos.api.ai.model.agent.EndpointSource;import com.alibaba.nacos.api.ai.model.agent.client.AgentPublishRequest;import com.alibaba.nacos.api.utils.json.JsonUtils;import java.util.Arrays;import java.util.Collections;import java.util.Map;import java.util.Properties;
Properties properties = new Properties();properties.setProperty("username", System.getenv("NACOS_USERNAME"));properties.setProperty("password", System.getenv("NACOS_PASSWORD"));properties.setProperty(PropertyKeyConst.SERVER_ADDR, "{serverAddr}");properties.setProperty(PropertyKeyConst.NAMESPACE, "{namespaceId}");
AgentInterface binding = new AgentInterface();binding.setUrl("https://agent.example.com:443/a2a");binding.setProtocolBinding("HTTP+JSON");binding.setProtocolVersion("1.0");
AgentCapabilities capabilities = new AgentCapabilities();capabilities.setStreaming(Boolean.TRUE);AgentCard card = new AgentCard();card.setName("{agentName}");card.setDescription("Order Agent");card.setVersion("1.0.0");card.setSupportedInterfaces(Collections.singletonList(binding));card.setCapabilities(capabilities);
Endpoint declaredEndpoint = new Endpoint();declaredEndpoint.setUri(binding.getUrl());declaredEndpoint.setTransport(binding.getProtocolBinding());
AgentCallInterface callInterface = new AgentCallInterface();callInterface.setProtocol("a2a");callInterface.setProtocolVersion("1.0");callInterface.setDescriptorMediaType("application/json");callInterface.setNativeDescriptor( JsonUtils.toObj(JsonUtils.toJson(card), Map.class));callInterface.setEndpointSourceOrder( Arrays.asList(EndpointSource.DECLARED, EndpointSource.RUNTIME));EndpointSet declaredSet = new EndpointSet();declaredSet.setSource(EndpointSource.DECLARED);declaredSet.setEndpoints(Collections.singletonList(declaredEndpoint));callInterface.setEndpointSets(Collections.singletonList(declaredSet));
AgentPublishRequest request = new AgentPublishRequest();request.setAgentName("{agentName}");request.setDisplayName("Order Agent");request.setVersion("1.0.0");request.setCallInterfaces(Collections.singletonList(callInterface));request.setAuthor("{author}");request.setChangeDescription("Initial version");request.setAutoSubmit(false); // A newly created first version still submits.
AiService aiService = AiFactory.createAiService(properties);try { AgentVersionDetail detail = aiService.agent().publishAgent(request); if ("online".equals(detail.getStatus())) { System.out.println("Version is online: " + detail.getVersion()); } else { System.out.println("Follow the publication workflow; current status: " + detail.getStatus()); }} finally { aiService.shutdown();}异常说明
请求为空、版本或定义校验失败、callInterfaces 和 basedOnVersion 未按二选一规则填写、并发冲突、提交失败,或服务端不支持此能力时,抛出 NacosException。
11.8. 获取 A2A 发现结果转换器
描述
从 3.3.0 开始,可以通过 a2aConverter() 获取本地转换器,将 RAD 的 AgentDiscoveryResult 显式转换为 Nacos SDK 的 AgentCard。获取和执行转换器不会查询 Nacos,客户端关闭后转换器仍可使用。发现和订阅不会自动执行转换。
方法签名
AgentConverter<AgentCard> a2aConverter();请求参数
无。
返回参数
| 参数类型 | 描述 |
|---|---|
| AgentConverter<AgentCard> | 可复用的无状态转换器,每次转换返回独立的 AgentCard,不修改输入快照。 |
请求示例
import com.alibaba.nacos.api.ai.converter.AgentConverter;import com.alibaba.nacos.api.ai.model.a2a.AgentCard;
// Reuse aiService, reference and filter from the discovery example.AgentConverter<AgentCard> converter = aiService.agent().a2aConverter();AgentDiscoveryResult snapshot = aiService.agent().discoverAgent(reference, filter);AgentCard card = converter.convert(snapshot);转换器按发现结果中的顺序选择第一个非空地址集合,不补回被 Filter 排除的地址,也不负责健康筛选。完整的回调转换示例见 RAD 发现。
异常说明
convert 在输入无效、没有 A2A 接口或地址、原生描述无效、名称或版本不一致时抛出 IllegalArgumentException。应用应处理转换失败;它不会变成订阅的 UNAVAILABLE 事件。
12. Java SDK的生命周期
Nacos Java SDK 实例从创建时开始持有线程池、连接、订阅等资源,调用 shutdown() 后释放。应用运行期间应复用实例,更换实例或退出时及时关闭,避免反复创建导致资源泄漏。
aiService.mcp()、agent()、skill()、agentSpec()、prompt() 共用父 AiService 的命名空间和生命周期,通过 aiService.shutdown() 统一关闭。Agent/MCP 运行端点应由注册它们的实例注销;取消订阅不会注销端点。应处理初次调用的同步错误;已接受的 RAD 订阅会在后台故障后保留并恢复,参见 SDK 运行指南。