Nacos系列:Nacos的Java SDK使用

Maven依赖

Nacos提供完整的Java SDK,便于配置管理和服务发现及管理,以 Nacos-0.8.0 版本为例

添加Maven依赖:

1<dependency> 2 <groupId>com.alibaba.nacos</groupId> 3 <artifactId>nacos-client</artifactId> 4 <version>0.8.0</version> 5</dependency>

仅仅引入nacos-client是不够的,否则启动时会出现如下错误:

1sun.misc.Launcher$AppClassLoader@18b4aac2 JM.Log:WARN Init JM logger with NopLoggerFactory, pay attention. sun.misc.Launcher$AppClassLoader@18b4aac2 2java.lang.ClassNotFoundException: org.apache.logging.log4j.core.Logger 3 at java.net.URLClassLoader.findClass(URLClassLoader.java:381) 4 at java.lang.ClassLoader.loadClass(ClassLoader.java:424) 5 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) 6 at java.lang.ClassLoader.loadClass(ClassLoader.java:357) 7 at java.lang.Class.forName0(Native Method) 8 at java.lang.Class.forName(Class.java:264) 9 at com.alibaba.nacos.client.logger.log4j2.Log4j2LoggerFactory.<init>(Log4j2LoggerFactory.java:33) 10 at com.alibaba.nacos.client.logger.LoggerFactory.<clinit>(LoggerFactory.java:59) 11 at com.alibaba.nacos.client.config.utils.LogUtils.<clinit>(LogUtils.java:49) 12 at com.alibaba.nacos.client.config.NacosConfigService.<clinit>(NacosConfigService.java:55) 13 at java.lang.Class.forName0(Native Method) 14 at java.lang.Class.forName(Class.java:264) 15 at com.alibaba.nacos.api.config.ConfigFactory.createConfigService(ConfigFactory.java:40) 16 at com.alibaba.nacos.api.config.ConfigFactory.createConfigService(ConfigFactory.java:59) 17 at com.alibaba.nacos.api.NacosFactory.createConfigService(NacosFactory.java:52) 18 at com.learn.nacos.config.NacosConfig.main(NacosConfig.java:12)

根据错误提示,应该还需要添加log4j相关依赖,官网的文档并没有对此说明,我在pom.xml添加了下面这些依赖才不报错

1<dependency> 2 <groupId>ch.qos.logback</groupId> 3 <artifactId>logback-classic</artifactId> 4 <version>1.1.11</version> 5</dependency> 6<dependency> 7 <groupId>org.logback-extensions</groupId> 8 <artifactId>logback-ext-spring</artifactId> 9 <version>0.1.4</version> 10</dependency> 11<dependency> 12 <groupId>org.slf4j</groupId> 13 <artifactId>jcl-over-slf4j</artifactId> 14 <version>1.7.25</version> 15</dependency> 16<dependency> 17 <groupId>log4j</groupId> 18 <artifactId>log4j</artifactId> 19 <version>1.2.17</version> 20</dependency> 21<dependency> 22 <groupId>org.slf4j</groupId> 23 <artifactId>slf4j-api</artifactId> 24 <version>1.7.25</version> 25</dependency>

配置管理

创建ConfigService,可以通过 NacosFactory.createConfigService()ConfigFactory.createConfigService() 来创建,后者是前者的底层实现方式,这两种方式都包含如下两个方法:

createConfigService(serverAddr) createConfigService(properties)

创建示例:

1// 方式一 2String serverAddr = "127.0.0.1:8848"; 3ConfigService configService = ConfigFactory.createConfigService(serverAddr); 4 5// 方式二 6ConfigService configService = ConfigFactory.createConfigService(properties) 7Properties properties = new Properties(); 8properties.put("serverAddr", serverAddr);

查看ConfigService源码,它提供了如下方法:

获取 Nacos Server 当前状态String getServerStatus()

底层源码:

1public String getServerStatus() { 2 if (worker.isHealthServer()) { 3 return "UP"; 4 } else { 5 return "DOWN"; 6 } 7}

根据源码注释,该状态应该是指 Nacos Server 的状态,我把 Nacos Server 关闭之后,再次运行示例,得到的结果仍然是UP,不知道这是不是一个BUG。

发布配置boolean publishConfig(String dataId, String group, String content) throws NacosException

支持程序自动发布Nacos配置,创建和修改配置使用同一个方法,配置不存在则创建;配置已存在则更新。

底层源码:

1try { 2 result = agent.httpPost(url, headers, params, encode, POST_TIMEOUT); 3} catch (IOException ioe) { 4 log.warn("NACOS-0006", 5 LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0006", "环境问题", "[publish-single] exception")); 6 log.warn(agent.getName(), "[publish-single] exception, dataId={}, group={}, msg={}", dataId, group, 7 ioe.toString()); 8 return false; 9}

发布配置后,如果马上用getConfig()读取配置,有时候会读不到,设置了足够的等待时长后才可保证每次正常读取,看了源码才知道Nacos的配置管理(发布、读取、移除)都是通过HTTP接口完成的,但发布配置的时延是多少,官网似乎没有说明?几秒钟的时延在一些对实时性要求很高的场景会不会存在影响呢?

读取配置String getConfig(String dataId, String group, long timeoutMs) throws NacosException

timeoutMs指读取配置超时时间,官网推荐设置为3000ms

底层源码:

1// 优先使用本地配置 2String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant); 3if (content != null) { 4 log.warn(agent.getName(), "[get-config] get failover ok, dataId={}, group={}, tenant={}, config={}", dataId, 5 group, tenant, ContentUtils.truncateContent(content)); 6 cr.setContent(content); 7 configFilterChainManager.doFilter(null, cr); 8 content = cr.getContent(); 9 return content; 10} 11 12try { 13 content = worker.getServerConfig(dataId, group, tenant, timeoutMs); 14 15 cr.setContent(content); 16 configFilterChainManager.doFilter(null, cr); 17 content = cr.getContent(); 18 19 return content; 20} catch (NacosException ioe) { 21 if (NacosException.NO_RIGHT == ioe.getErrCode()) { 22 throw ioe; 23 } 24 log.warn("NACOS-0003", 25 LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0003", "环境问题", "get from server error")); 26 log.warn(agent.getName(), "[get-config] get from server error, dataId={}, group={}, tenant={}, msg={}", 27 dataId, group, tenant, ioe.toString()); 28}

从源码上看,配置会先从本地缓存文件读取,如果没读取到,才会去请求Nacos Server的配置,这个缓存文件在哪呢?就在当前用户的nacos目录下 生成的缓存文件:nacos/config/fixed-127.0.0.1_8848_nacos/snapshot/DEFAULT_GROUP/nacos-sdk-java-config,配置内容和发布到Nacos Server的配置内容是一致的。

移除配置boolean removeConfig(String dataId, String group) throws NacosException

支持程序自动发布Nacos配置,配置不存在时会直接返回成功,移除配置后,本地的缓存文件也会被删除

底层源码:

1try { 2 result = agent.httpDelete(url, null, params, encode, POST_TIMEOUT); 3} catch (IOException ioe) { 4 log.warn("[remove] error, " + dataId + ", " + group + ", " + tenant + ", msg: " + ioe.toString()); 5 return false; 6}

移除配置同发布配置一样,如果移除后马上查询,有可能还能将刚移除的配置查出来,也存在一定的时延,需要设置等待时间读取。

添加配置监听void addListener(String dataId, String group, Listener listener) throws NacosException

支持动态监听配置的变化,运行示例源码,在Nacos控制台把配置内容修改为sdk-java-config:change from nacos console,此时观看IDE控制台,你会看到如下打印信息:

当前线程:com.alibaba.nacos.client.Worker.longPollingfixed-127.0.0.1_8848 ,监听到配置内容变化:sdk-java-config:change from nacos console

移除配置监听void removeListener(String dataId, String group, Listener listener)

移除监听后,配置的变化不会再监听

启动完整示例,运行结果如下,请注意配置监听线程和配置管理线程不是同一个线程

1当前线程:main ,服务状态:UP 2添加监听 3添加监听成功 4发布配置 5发布配置成功 6当前线程:com.alibaba.nacos.client.Worker.longPollingfixed-127.0.0.1_8848 ,监听到配置内容变化:nacos-sdk-java-config:init 7当前线程:main ,发布配置后获取配置内容:nacos-sdk-java-config:init 8重新发布配置 9重新发布配置成功 10当前线程:main ,重新发布配置后获取配置内容:sdk-java-config:update 11当前线程:com.alibaba.nacos.client.Worker.longPollingfixed-127.0.0.1_8848 ,监听到配置内容变化:sdk-java-config:update 12当前线程:com.alibaba.nacos.client.Worker.longPollingfixed-127.0.0.1_8848 ,监听到配置内容变化:sdk-java-config:change from nacos console 13移除配置 14移除配置成功 15当前线程:main ,移除配置后获取配置内容:null 16取消监听 17取消监听成功

服务管理

创建NamingService,可以通过 NacosFactory.createNamingService()NamingFactory.createNamingService() 来创建,后者是前者的底层实现方式,这两种方式都包含如下两个方法:

createNamingService(serverAddr) createNamingService(properties)

创建示例:

1// 方式一 2String serverAddr = "127.0.0.1:8848"; 3NamingService namingService = NamingFactory.createNamingService(serverAddr); 4 5// 方式二 6NamingService namingService = NamingFactory.createNamingService(properties) 7Properties properties = new Properties(); 8properties.put("serverAddr", serverAddr);

查看NamingService类源码,它提供了如下方法:

获取 Nacos Server 当前状态String getServerStatus()

注册服务实例void registerInstance(多个参数)

1方式一: 2String serverIp = "127.0.0.1"; 3int serverPort = 8848; 4String serverAddr = serverIp + ":" + serverPort; 5String serviceName = "nacos-sdk-java-discovery"; 6NamingService namingService = NamingFactory.createNamingService(serverAddr); 7namingService.registerInstance(serviceName, serverIp, serverPort); 8 9方式二: 10Instance instance = new Instance(); 11instance.setIp(serverIp);//IP 12instance.setPort(serverPort);//端口 13instance.setServiceName(serviceName);//服务名 14instance.setEnabled(true);//true: 上线 false: 下线 15instance.setHealthy(healthy);//健康状态 16instance.setWeight(1.0);//权重 17instance.addMetadata("nacos-sdk-java-discovery", "true");//元数据 18NamingService namingService = NamingFactory.createNamingService(serverAddr); 19namingService.registerInstance(serviceName, instance);

注册后,本地会生成缓存文件 1、在Nacos安装目录data目录下:data/naming/data/public/com.alibaba.nacos.naming.domains.meta.public##nacos-sdk-java-discovery 2、当前用户的nacos目录下:/nacos/naming/public/failover/nacos-sdk-java-discovery 3、当前用户的nacos目录下:/nacos/naming/public/nacos-sdk-java-discovery

即使删除服务实例,上面三个缓存文件也不会被删除,Nacos控制台服务列表中该服务也还存在着(但服务实例数会变成0);删除Nacos控制台的该服务,安全目录data目录下的缓存文件会被删除,但当前用户的nacos目录下的文件不会被删除,这里面是什么机制,我暂时还没整明白,等后面整明白了再来补充。

删除服务实例void deregisterInstance(多个参数)

获取所有服务实例List<Instance> getAllInstances(多个参数)

获取所有健康或不健康的服务实例List<Instance> selectInstances(多个参数)

随机获取一个健康实例(根据负载均衡算法)Instance selectOneHealthyInstance(多个参数)

添加服务实例监听void subscribe(多个参数)

添加服务实例监听void unsubscribe(多个参数)

分页获取所有服务实例ListView<String> getServicesOfServer(多个参数)

获取所有监听的服务实例List<ServiceInfo> getSubscribeServices()

启动完整示例,运行结果如下,请注意服务实例监听线程和服务实例管理线程不是同一个线程

1当前线程:main ,服务状态:UP 2注册实例 3注册实例成功 4添加监听 5添加监听成功 6当前线程:main ,注册实例后获取所有实例:[{"clusterName":"DEFAULT","enabled":true,"instanceId":"127.0.0.1#8848#DEFAULT#nacos-sdk-java-discovery","ip":"127.0.0.1","metadata":{},"port":8848,"serviceName":"nacos-sdk-java-discovery","valid":true,"weight":1.0}] 7当前线程:main ,注册实例后获取所有健康实例:[{"clusterName":"DEFAULT","enabled":true,"instanceId":"127.0.0.1#8848#DEFAULT#nacos-sdk-java-discovery","ip":"127.0.0.1","metadata":{},"port":8848,"serviceName":"nacos-sdk-java-discovery","valid":true,"weight":1.0}] 8当前线程:com.alibaba.nacos.naming.client.listener ,监听到实例名称:nacos-sdk-java-discovery 9当前线程:com.alibaba.nacos.naming.client.listener ,监听到实例内容:[{"clusterName":"DEFAULT","enabled":true,"instanceId":"127.0.0.1#8848#DEFAULT#nacos-sdk-java-discovery","ip":"127.0.0.1","metadata":{},"port":8848,"serviceName":"nacos-sdk-java-discovery","valid":true,"weight":1.0}] 10当前线程:main ,注册实例后获取一个健康实例:{"clusterName":"DEFAULT","enabled":true,"instanceId":"127.0.0.1#8848#DEFAULT#nacos-sdk-java-discovery","ip":"127.0.0.1","metadata":{},"port":8848,"serviceName":"nacos-sdk-java-discovery","valid":true,"weight":1.0} 11当前线程:com.alibaba.nacos.naming.client.listener ,监听到实例名称:nacos-sdk-java-discovery 12当前线程:com.alibaba.nacos.naming.client.listener ,监听到实例内容:[{"clusterName":"DEFAULT","enabled":true,"instanceId":"127.0.0.1#8848#DEFAULT#nacos-sdk-java-discovery","ip":"127.0.0.1","metadata":{"change":"true;"},"port":8848,"serviceName":"nacos-sdk-java-discovery","valid":true,"weight":2.0}] 13取消监听 14取消监听成功 15删除实例 16删除实例成功 17Exception in thread "main" java.lang.IllegalStateException: no host to srv for serviceInfo: nacos-sdk-java-discovery 18 at com.alibaba.nacos.client.naming.core.Balancer$RandomByWeight.selectAll(Balancer.java:45) 19 at com.alibaba.nacos.client.naming.core.Balancer$RandomByWeight.selectHost(Balancer.java:53) 20 at com.alibaba.nacos.client.naming.NacosNamingService.selectOneHealthyInstance(NacosNamingService.java:270) 21 at com.alibaba.nacos.client.naming.NacosNamingService.selectOneHealthyInstance(NacosNamingService.java:263) 22 at com.alibaba.nacos.client.naming.NacosNamingService.selectOneHealthyInstance(NacosNamingService.java:253) 23 at com.learn.nacos.discovery.NacosDiscovery.main(NacosDiscovery.java:121) 24当前线程:main ,删除实例后获取所有实例:[] 25当前线程:main ,删除实例后获取所有健康实例:[]

以上就是 Nacos Java SDK 配置管理和服务管理功能的介绍,请参考示例源码学习。

示例源码

项目:learn-nacos-sdk-java

代码已上传至码云Github上,欢迎下载学习

参考资料

推荐阅读

点赞
收藏

评论区

加载中...

相关推荐

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Nacos发布 v0.2 版本,无缝支持 Spring Cloud 微服务生态及高可用集群模式

_摘要:_ 近日,阿里巴巴新开源项目Nacos发布了v0.2版本,该版本开始支持完整的Spring生态技术栈,这包括SpringFramework、SpringBoot和SpringCloud。为了让更多的Spring用户可以在生产上基于Nacos做微服务平台的服务发现、配置管理、服务管控,Nacosv0.2版本向下兼容了大部分Spri

IDEA 安装lombok及使用

1、FileSettingsPluginsBrowsRepositories输入lombokinstall2、重启idea3、添加maven依赖<dependency  <groupIdorg.projectlombok</groupId  <artifactIdlombok</artifactId  <v

Nutz 集成 Flowable 6.4.2 工作流 完全兼容 Activiti

废话不多说直接上代码。项目完整源码链接(https://gitee.com/threefish/NutzFw)1、添加maven依赖包<dependency<groupIdorg.flowable</groupId<artifactId

SpringMVC 支持Hibernate Validator

一、基础框架SpringMVC4.0.3.RELEASE,使用的maven来管理jar依赖二、依赖的jar,  <dependency         <groupIdorg.hibernate</groupId         <artifactIdhibernatevalidator</artifactI

Nacos系列:Nacos的Java SDK使用 - HelloWorld