Nacos提供完整的Java SDK,便于配置管理和服务发现及管理,以 Nacos-0.8.0
版本为例html
添加Maven依赖:java
<dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>0.8.0</version> </dependency>
仅仅引入nacos-client
是不够的,不然启动时会出现以下错误:git
sun.misc.Launcher$AppClassLoader@18b4aac2 JM.Log:WARN Init JM logger with NopLoggerFactory, pay attention. sun.misc.Launcher$AppClassLoader@18b4aac2 java.lang.ClassNotFoundException: org.apache.logging.log4j.core.Logger at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:264) at com.alibaba.nacos.client.logger.log4j2.Log4j2LoggerFactory.<init>(Log4j2LoggerFactory.java:33) at com.alibaba.nacos.client.logger.LoggerFactory.<clinit>(LoggerFactory.java:59) at com.alibaba.nacos.client.config.utils.LogUtils.<clinit>(LogUtils.java:49) at com.alibaba.nacos.client.config.NacosConfigService.<clinit>(NacosConfigService.java:55) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:264) at com.alibaba.nacos.api.config.ConfigFactory.createConfigService(ConfigFactory.java:40) at com.alibaba.nacos.api.config.ConfigFactory.createConfigService(ConfigFactory.java:59) at com.alibaba.nacos.api.NacosFactory.createConfigService(NacosFactory.java:52) at com.learn.nacos.config.NacosConfig.main(NacosConfig.java:12)
根据错误提示,应该还须要添加log4j
相关依赖,官网的文档并无对此说明,我在pom.xml
添加了下面这些依赖才不报错github
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.11</version> </dependency> <dependency> <groupId>org.logback-extensions</groupId> <artifactId>logback-ext-spring</artifactId> <version>0.1.4</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency>
建立ConfigService
,能够经过 NacosFactory.createConfigService()
或 ConfigFactory.createConfigService()
来建立,后者是前者的底层实现方式,这两种方式都包含以下两个方法:createConfigService(serverAddr)
createConfigService(properties)
算法
建立示例:spring
// 方式一 String serverAddr = "127.0.0.1:8848"; ConfigService configService = ConfigFactory.createConfigService(serverAddr); // 方式二 ConfigService configService = ConfigFactory.createConfigService(properties) Properties properties = new Properties(); properties.put("serverAddr", serverAddr);
查看ConfigService
源码,它提供了以下方法:apache
获取 Nacos Server 当前状态:String getServerStatus()
底层源码:c#
public String getServerStatus() { if (worker.isHealthServer()) { return "UP"; } else { return "DOWN"; } }
根据源码注释,该状态应该是指 Nacos Server 的状态,我把 Nacos Server 关闭以后,再次运行示例,获得的结果仍然是
UP
,不知道这是否是一个BUG。
发布配置:boolean publishConfig(String dataId, String group, String content) throws NacosException
支持程序自动发布Nacos配置,建立和修改配置使用同一个方法,配置不存在则建立;配置已存在则更新。segmentfault
底层源码:api
try { result = agent.httpPost(url, headers, params, encode, POST_TIMEOUT); } catch (IOException ioe) { log.warn("NACOS-0006", LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0006", "环境问题", "[publish-single] exception")); log.warn(agent.getName(), "[publish-single] exception, dataId={}, group={}, msg={}", dataId, group, ioe.toString()); return false; }
发布配置后,若是立刻用getConfig()读取配置,有时候会读不到,设置了足够的等待时长后才可保证每次正常读取,看了源码才知道Nacos的配置管理(发布、读取、移除)都是经过HTTP接口完成的,但发布配置的时延是多少,官网彷佛没有说明?几秒钟的时延在一些对实时性要求很高的场景会不会存在影响呢?
读取配置:String getConfig(String dataId, String group, long timeoutMs) throws NacosException
timeoutMs指读取配置超时时间,官网推荐设置为3000
ms
底层源码:
// 优先使用本地配置 String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant); if (content != null) { log.warn(agent.getName(), "[get-config] get failover ok, dataId={}, group={}, tenant={}, config={}", dataId, group, tenant, ContentUtils.truncateContent(content)); cr.setContent(content); configFilterChainManager.doFilter(null, cr); content = cr.getContent(); return content; } try { content = worker.getServerConfig(dataId, group, tenant, timeoutMs); cr.setContent(content); configFilterChainManager.doFilter(null, cr); content = cr.getContent(); return content; } catch (NacosException ioe) { if (NacosException.NO_RIGHT == ioe.getErrCode()) { throw ioe; } log.warn("NACOS-0003", LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0003", "环境问题", "get from server error")); log.warn(agent.getName(), "[get-config] get from server error, dataId={}, group={}, tenant={}, msg={}", dataId, group, tenant, ioe.toString()); }
从源码上看,配置会先从本地缓存文件读取,若是没读取到,才会去请求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配置,配置不存在时会直接返回成功,移除配置后,本地的缓存文件也会被删除
底层源码:
try { result = agent.httpDelete(url, null, params, encode, POST_TIMEOUT); } catch (IOException ioe) { log.warn("[remove] error, " + dataId + ", " + group + ", " + tenant + ", msg: " + ioe.toString()); return false; }
移除配置同发布配置同样,若是移除后立刻查询,有可能还能将刚移除的配置查出来,也存在必定的时延,须要设置等待时间读取。
添加配置监听: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)
移除监听后,配置的变化不会再监听
启动完整示例,运行结果以下,请注意配置监听线程和配置管理线程不是同一个线程
当前线程:main ,服务状态:UP 添加监听 添加监听成功 发布配置 发布配置成功 当前线程:com.alibaba.nacos.client.Worker.longPollingfixed-127.0.0.1_8848 ,监听到配置内容变化:nacos-sdk-java-config:init 当前线程:main ,发布配置后获取配置内容:nacos-sdk-java-config:init 从新发布配置 从新发布配置成功 当前线程:main ,从新发布配置后获取配置内容:sdk-java-config:update 当前线程:com.alibaba.nacos.client.Worker.longPollingfixed-127.0.0.1_8848 ,监听到配置内容变化:sdk-java-config:update 当前线程:com.alibaba.nacos.client.Worker.longPollingfixed-127.0.0.1_8848 ,监听到配置内容变化:sdk-java-config:change from nacos console 移除配置 移除配置成功 当前线程:main ,移除配置后获取配置内容:null 取消监听 取消监听成功
建立NamingService
,能够经过 NacosFactory.createNamingService()
或 NamingFactory.createNamingService()
来建立,后者是前者的底层实现方式,这两种方式都包含以下两个方法:createNamingService(serverAddr)
createNamingService(properties)
建立示例:
// 方式一 String serverAddr = "127.0.0.1:8848"; NamingService namingService = NamingFactory.createNamingService(serverAddr); // 方式二 NamingService namingService = NamingFactory.createNamingService(properties) Properties properties = new Properties(); properties.put("serverAddr", serverAddr);
查看NamingService
类源码,它提供了以下方法:
获取 Nacos Server 当前状态:String getServerStatus()
注册服务实例:void registerInstance(多个参数)
方式一: String serverIp = "127.0.0.1"; int serverPort = 8848; String serverAddr = serverIp + ":" + serverPort; String serviceName = "nacos-sdk-java-discovery"; NamingService namingService = NamingFactory.createNamingService(serverAddr); namingService.registerInstance(serviceName, serverIp, serverPort); 方式二: Instance instance = new Instance(); instance.setIp(serverIp);//IP instance.setPort(serverPort);//端口 instance.setServiceName(serviceName);//服务名 instance.setEnabled(true);//true: 上线 false: 下线 instance.setHealthy(healthy);//健康状态 instance.setWeight(1.0);//权重 instance.addMetadata("nacos-sdk-java-discovery", "true");//元数据 NamingService namingService = NamingFactory.createNamingService(serverAddr); namingService.registerInstance(serviceName, instance);
注册后,本地会生成缓存文件
一、在Nacos安装目录data目录下:data/naming/data/public/com.alibaba.nacos.naming.domains.meta.public##nacos-sdk-java-discovery
二、当前用户的nacos目录下:/nacos/naming/public/failover/nacos-sdk-java-discovery
三、当前用户的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()
启动完整示例,运行结果以下,请注意服务实例监听线程和服务实例管理线程不是同一个线程
当前线程:main ,服务状态:UP 注册实例 注册实例成功 添加监听 添加监听成功 当前线程: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}] 当前线程: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}] 当前线程:com.alibaba.nacos.naming.client.listener ,监听到实例名称:nacos-sdk-java-discovery 当前线程: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}] 当前线程: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} 当前线程:com.alibaba.nacos.naming.client.listener ,监听到实例名称:nacos-sdk-java-discovery 当前线程: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}] 取消监听 取消监听成功 删除实例 删除实例成功 Exception in thread "main" java.lang.IllegalStateException: no host to srv for serviceInfo: nacos-sdk-java-discovery at com.alibaba.nacos.client.naming.core.Balancer$RandomByWeight.selectAll(Balancer.java:45) at com.alibaba.nacos.client.naming.core.Balancer$RandomByWeight.selectHost(Balancer.java:53) at com.alibaba.nacos.client.naming.NacosNamingService.selectOneHealthyInstance(NacosNamingService.java:270) at com.alibaba.nacos.client.naming.NacosNamingService.selectOneHealthyInstance(NacosNamingService.java:263) at com.alibaba.nacos.client.naming.NacosNamingService.selectOneHealthyInstance(NacosNamingService.java:253) at com.learn.nacos.discovery.NacosDiscovery.main(NacosDiscovery.java:121) 当前线程:main ,删除实例后获取全部实例:[] 当前线程:main ,删除实例后获取全部健康实例:[]
以上就是 Nacos Java SDK 配置管理和服务管理功能的介绍,请参考示例源码学习。
项目:learn-nacos-sdk-java
代码已上传至码云
和Github
上,欢迎下载学习