Nacos 注册中心实现原理,及服务注册源码分析
1、关于 Nacos
Nacos 的关键特性包括:
- 服务发现和服务健康监测。
- 动态配置服务。
- 动态 DNS 服务。
- 服务及其元数据管理
2、Nacos 架构图
3、Nacos 注册中心原理
服务注册的功能主要体现在以下几个方面:
- 服务实例在启动时注册到服务注册列表,并在关闭时注销。
- 服务消费者查询服务注册列表,获得可用实例。
- 服务注册中心需要调用服务实例的健康检查 API ,来验证服务提供者是否能够处理请求。
4、Spring Cloud 框架下 Nacos 的服务注册
- 带着一个问题,往下看博文:
Spring Cloud 是何时完成服务注册的 ?
4.1、先从 spring.factory 文件说起
- spring.factory 文件的功能
springboot项目开发过程中,我们加载自己写的bean,只需要在该类上加上@Component注解,然后过程启动会扫描启动类所在的包及其子包。有些场景是我们需要的bean,在第三方包中就不好使用@Component注解。当然不排除通过其他注解可以import进来。我们要知道使用spring.factories文件的方法,也可以解决这种问题。
假设我们有一个xxx.jar包,里面有一个bean,我们期望工程启动的时候就加载这个bean到容器,xxx.jar包是提供给其他人使用的,其他工程的启动了类所在的路径不能覆盖这个bean所在的包路径,通过ComponouneScan扫描太麻烦了,而且需求是工程启动后就加载bean,我们可以使用spring.factories文件的方法。
在xxx.jar包下面的resources下面新建文件/META-INF/spring.factories文件,在spring.factories文件中配置相关需要加载的类即可。具体请详细查询spring.factories文件用法,这里知识简要说明spring.factories文件的功能。
4.2、Spring Cloud 集成 Nacos 的过程
在 spring-cloud-commons 包的 /META-INF/spring.factories 文件中,包含了自动装配的配置信息,见以下截图,其中包含类:org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration
4.3、客户端 服务注册、心跳检测的源码分析
- 注意,以下源码的版本为:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>0.2.1.RELEASE</version>
</dependency>
- 1、看
AutoServiceRegistrationAutoConfiguration
类源码,可以看到它注入了AutoServiceRegistration
实例。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.cloud.client.serviceregistry;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({AutoServiceRegistrationConfiguration.class})
@ConditionalOnProperty(
value = {"spring.cloud.service-registry.auto-registration.enabled"},
matchIfMissing = true
)
public class AutoServiceRegistrationAutoConfiguration {
@Autowired(
required = false
)
// 注入 AutoServiceRegistration 实例
private AutoServiceRegistration autoServiceRegistration;
@Autowired
private AutoServiceRegistrationProperties properties;
public AutoServiceRegistrationAutoConfiguration() {
}
@PostConstruct
protected void init() {
if (this.autoServiceRegistration == null && this.properties.isFailFast()) {
throw new IllegalStateException("Auto Service Registration has been requested, but there is no AutoServiceRegistration bean");
}
}
}
- 2、查看
AutoServiceRegistration
相关类图,AbstractAutoServiceRegistration 抽象类
实现了AutoServiceRegistration 接口类
,NacosAutoServiceRegistration
类继承了AbstractAutoServiceRegistration 抽象类
。
- 3、分析下
AbstractAutoServiceRegistration 抽象类
源码,具体看源码中添加的注释说明。
package org.springframework.cloud.client.serviceregistry;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.PreDestroy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.cloud.client.discovery.ManagementServerPortUtils;
import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent;
import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.Environment;
public abstract class AbstractAutoServiceRegistration<R extends Registration> implements AutoServiceRegistration,
ApplicationContextAware {
private static final Log logger = LogFactory.getLog(AbstractAutoServiceRegistration.class);
private boolean autoStartup = true;
private AtomicBoolean running = new AtomicBoolean(false);
private int order = 0;
private ApplicationContext context;
private Environment environment;
private AtomicInteger port = new AtomicInteger(0);
// 这里是服务注册 ServiceRegistry 接口类, NacosAutoServiceRegistration 继承 AbstractAutoServiceRegistration 时,
// 指定了 R 为 NacosRegistration
private final ServiceRegistry<R> serviceRegistry;
private AutoServiceRegistrationProperties properties;
protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry,
AutoServiceRegistrationProperties properties) {
this.serviceRegistry = serviceRegistry;
this.properties = properties;
}
protected ApplicationContext getContext() {
return this.context;
}
// @EventListener 事件监听机制,监听某个指定事件。这里 @EventListener({WebServerInitializedEvent.class}) 表示:
// 监听 WebServerInitializedEvent 事件(当 Webserver 初始化完成之后)执行
@EventListener({WebServerInitializedEvent.class})
public void bind(WebServerInitializedEvent event) {
ApplicationContext context = event.getApplicationContext();
if (!(context instanceof ConfigurableWebServerApplicationContext) ||
!"management".equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) {
this.port.compareAndSet(0, event.getWebServer().getPort());
// 执行start()方法,往下详细看该类 start() 方法
this.start();
}
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
this.environment = this.context.getEnvironment();
}
public boolean isAutoStartup() {
return this.autoStartup;
}
public void start() {
if (!this.isEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Discovery Lifecycle disabled. Not starting");
}
} else {
if (!this.running.get()) {
this.context.publishEvent(new InstancePreRegisteredEvent(this, this.getRegistration()));
// 这里调用 该类中注册方法,往下详细看 register() 方法
this.register();
if (this.shouldRegisterManagement()) {
this.registerManagement();
}
this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));
this.running.compareAndSet(false, true);
}
}
}
protected boolean shouldRegisterManagement() {
if (this.properties != null && !this.properties.isRegisterManagement()) {
return false;
} else {
return this.getManagementPort() != null && ManagementServerPortUtils.isDifferent(this.context);
}
}
// ……
// 该类中的部分方法函数,在此次删减掉了。想详细了解该类,可以看相关完整源码。此处仅详细关注服务注册相关。
// ……
protected ServiceRegistry<R> getServiceRegistry() {
return this.serviceRegistry;
}
protected void register() {
// 这里调用 serviceRegistry 接口类中的 register() 方法。
// 往下深究你会发现,NacosServiceRegistry implements ServiceRegistry<NacosRegistration>
// NacosServiceRegistry 类实现了 ServiceRegistry 接口类
this.serviceRegistry.register(this.getRegistration());
}
protected void registerManagement() {
R registration = this.getManagementRegistration();
if (registration != null) {
this.serviceRegistry.register(registration);
}
}
protected void deregister() {
this.serviceRegistry.deregister(this.getRegistration());
}
protected void deregisterManagement() {
R registration = this.getManagementRegistration();
if (registration != null) {
this.serviceRegistry.deregister(registration);
}
}
public void stop() {
if (this.getRunning().compareAndSet(true, false) && this.isEnabled()) {
this.deregister();
if (this.shouldRegisterManagement()) {
this.deregisterManagement();
}
this.serviceRegistry.close();
}
}
}
- 4、
NacosAutoServiceRegistration 类
源码分析
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.cloud.alibaba.nacos.registry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
// NacosAutoServiceRegistration 继承了 AbstractAutoServiceRegistration 抽象类,并指定了 NacosRegistration
public class NacosAutoServiceRegistration extends AbstractAutoServiceRegistration<NacosRegistration> {
private static final Logger LOGGER = LoggerFactory.getLogger(NacosAutoServiceRegistration.class);
@Autowired
private NacosRegistration registration;
public NacosAutoServiceRegistration(ServiceRegistry<NacosRegistration> serviceRegistry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
super(serviceRegistry, autoServiceRegistrationProperties);
this.registration = registration;
}
/** @deprecated */
@Deprecated
public void setPort(int port) {
this.getPort().set(port);
}
protected NacosRegistration getRegistration() {
if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
this.registration.setPort(this.getPort().get());
}
Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
return this.registration;
}
protected NacosRegistration getManagementRegistration() {
return null;
}
// 重点是该方法
protected void register() {
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
LOGGER.debug("Registration disabled.");
} else {
// NacosRegistration 设置相关参数
if (this.registration.getPort() < 0) {
this.registration.setPort(this.getPort().get());
}
// 最终还是调用了 父类 AbstractAutoServiceRegistration 的 register 方法。
super.register();
}
}
protected void registerManagement() {
if (this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
super.registerManagement();
}
}
protected Object getConfiguration() {
return this.registration.getNacosDiscoveryProperties();
}
protected boolean isEnabled() {
return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
}
protected String getAppName() {
String appName = this.registration.getNacosDiscoveryProperties().getService();
return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
}
}
- 5、
NacosServiceRegistry 类
源码分析,实现了ServiceRegistry< NacosRegistration>
接口类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.cloud.alibaba.nacos.registry;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.StringUtils;
public class NacosServiceRegistry implements ServiceRegistry<NacosRegistration> {
private static Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class);
public NacosServiceRegistry() {
}
// 主要是该方法,实现了 ServiceRegistry 接口类的 register(Registration) 方法
public void register(NacosRegistration registration) {
if (!registration.isRegisterEnabled()) {
logger.info("Nacos Registration is disabled...");
} else if (StringUtils.isEmpty(registration.getServiceId())) {
logger.info("No service to register for nacos client...");
} else {
// 获取到 NamingService 服务
NamingService namingService = registration.getNacosNamingService();
String serviceId = registration.getServiceId();
Instance instance = new Instance();
instance.setIp(registration.getHost());
instance.setPort(registration.getPort());
instance.setWeight((double)registration.getRegisterWeight());
instance.setClusterName(registration.getCluster());
instance.setMetadata(registration.getMetadata());
try {
// 通过该方法,进行服务注册
namingService.registerInstance(serviceId, instance);
logger.info("nacos registry, {} {}:{} register finished", new Object[]{serviceId, instance.getIp(), instance.getPort()});
} catch (Exception var6) {
logger.error("nacos registry, {} register failed...{},", new Object[]{serviceId, registration.toString(), var6});
}
}
}
public void deregister(NacosRegistration registration) {
logger.info("De-registering from Nacos Server now...");
if (StringUtils.isEmpty(registration.getServiceId())) {
logger.info("No dom to de-register for nacos client...");
} else {
NamingService namingService = registration.getNacosNamingService();
String serviceId = registration.getServiceId();
try {
namingService.deregisterInstance(serviceId, registration.getHost(), registration.getPort(), registration.getCluster());
} catch (Exception var5) {
logger.error("ERR_NACOS_DEREGISTER, de-register failed...{},", registration.toString(), var5);
}
logger.info("De-registration finished.");
}
}
public void close() {
}
public void setStatus(NacosRegistration registration, String status) {
}
public <T> T getStatus(NacosRegistration registration) {
return null;
}
}
- 6、
NacosNamingService 类
源码分析,实现了NamingService
接口类
public class NacosNamingService implements NamingService {
private String namespace;
private String endpoint;
private String serverList;
private String cacheDir;
private String logName;
private HostReactor hostReactor;
private BeatReactor beatReactor;
private EventDispatcher eventDispatcher;
private NamingProxy serverProxy;
private void init() {
this.namespace = System.getProperty("namespace");
if (StringUtils.isEmpty(this.namespace)) {
this.namespace = "default";
}
this.logName = System.getProperty("com.alibaba.nacos.naming.log.filename");
if (StringUtils.isEmpty(this.logName)) {
this.logName = "naming.log";
}
String logLevel = System.getProperty("com.alibaba.nacos.naming.log.level");
if (StringUtils.isEmpty(logLevel)) {
logLevel = "INFO";
}
LogUtils.setLogLevel(logLevel);
this.cacheDir = System.getProperty("com.alibaba.nacos.naming.cache.dir");
if (StringUtils.isEmpty(this.cacheDir)) {
this.cacheDir = System.getProperty("user.home") + "/nacos/naming/" + this.namespace;
}
}
public NacosNamingService(String serverList) {
this.serverList = serverList;
this.init();
this.eventDispatcher = new EventDispatcher();
this.serverProxy = new NamingProxy(this.namespace, this.endpoint, serverList);
this.beatReactor = new BeatReactor(this.serverProxy);
this.hostReactor = new HostReactor(this.eventDispatcher, this.serverProxy, this.cacheDir, false);
}
// 上面 5、中调用 namingService.registerInstance(serviceId, instance); 的具体实现
public void registerInstance(String serviceName, Instance instance) throws NacosException {
BeatInfo beatInfo = new BeatInfo();
beatInfo.setDom(serviceName);
beatInfo.setIp(instance.getIp());
beatInfo.setPort(instance.getPort());
beatInfo.setCluster(instance.getClusterName());
beatInfo.setWeight(instance.getWeight());
beatInfo.setMetadata(instance.getMetadata());
// 通过 beatReactor.addBeatInfo 方法 创建心跳信息实现健康检测,
// Nacos Server 必须要确保注册的服务实例是健康的
// 心跳检测就是服务健康检测的手段。详细见下面第 7步
this.beatReactor.addBeatInfo(serviceName, beatInfo);
// serverProxy.registerService 方法实现服务注册,详情见下面第 8步
this.serverProxy.registerService(serviceName, instance);
}
// ……
// 该类的源码在这里被省略部分方法,如需了解该类完整源码,可查看相关文档。
// ……
- 7、
BeatReactor 类
源码分析 心跳检测机制,从源码上来看,所谓的心跳检测机制,就是客户端定时的向服务端发送请求。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.alibaba.nacos.client.naming.beat;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.client.naming.net.NamingProxy;
import com.alibaba.nacos.client.naming.utils.LogUtils;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
public class BeatReactor {
// 定时调度线程池 ScheduledThreadPoolExecutor 做定时任务处理
private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
// 设置线程为“守护线程”
thread.setDaemon(true);
// BeatReactor 会启动名为 com.alibaba.nacos.naming.beat.sender 的线程来发送心跳,
// 默认线程数为1~CPU核心数的一半,可由namingClientBeatThreadCount参数指定。
thread.setName("com.alibaba.nacos.naming.beat.sender");
return thread;
}
});
// 这里定义了默认 5秒 发送一次心跳,可根据Nacos服务端返回的clientBeatInterval的值调整心跳间隔。
private long clientBeatInterval = 5000L;
private NamingProxy serverProxy;
// 成员变量Map<String, BeatInfo> dom2Beat 中保存了需要发送的 BeatInfo,
// key为{serviceName}#{ip}#{port},value为对应的BeatInfo
public final Map<String, BeatInfo> dom2Beat = new ConcurrentHashMap();
public BeatReactor(NamingProxy serverProxy) {
this.serverProxy = serverProxy;
// scheduleAtFixedRate 方法的左右是指定频率执行方法
// 这里指 每5秒执行一次 new BeatReactor.BeatProcessor() 。 clientBeatInterval指执行间隔,默认为5秒
this.executorService.scheduleAtFixedRate(new BeatReactor.BeatProcessor(), 0L, this.clientBeatInterval, TimeUnit.MILLISECONDS);
}
// 此处衔接上面第 6 步
public void addBeatInfo(String dom, BeatInfo beatInfo) {
LogUtils.LOG.info("BEAT", "adding service:" + dom + " to beat map.");
this.dom2Beat.put(this.buildKey(dom, beatInfo.getIp(), beatInfo.getPort()), beatInfo);
}
public void removeBeatInfo(String dom, String ip, int port) {
LogUtils.LOG.info("BEAT", "removing service:" + dom + " from beat map.");
this.dom2Beat.remove(this.buildKey(dom, ip, port));
}
// 拼接key 值,key为{serviceName}#{ip}#{port}
public String buildKey(String dom, String ip, int port) {
return dom + "#" + ip + "#" + port;
}
class BeatTask implements Runnable {
BeatInfo beatInfo;
public BeatTask(BeatInfo beatInfo) {
this.beatInfo = beatInfo;
}
public void run() {
Map<String, String> params = new HashMap(2);
params.put("beat", JSON.toJSONString(this.beatInfo));
params.put("dom", this.beatInfo.getDom());
try {
// 获取到 服务端的回应,这里找下去就是一个 http 请求
String result = BeatReactor.this.serverProxy.callAllServers("/nacos/v1/ns/api/clientBeat", params);
JSONObject jsonObject = JSON.parseObject(result);
if (jsonObject != null) {
BeatReactor.this.clientBeatInterval = jsonObject.getLong("clientBeatInterval");
}
} catch (Exception var4) {
LogUtils.LOG.error("CLIENT-BEAT", "failed to send beat: " + JSON.toJSONString(this.beatInfo), var4);
}
}
}
class BeatProcessor implements Runnable {
BeatProcessor() {
}
public void run() {
try {
Iterator var1 = BeatReactor.this.dom2Beat.entrySet().iterator();
while(var1.hasNext()) {
Entry<String, BeatInfo> entry = (Entry)var1.next();
BeatInfo beatInfo = (BeatInfo)entry.getValue();
// executor. schedule(Runnable command, long delay, TimeUnit unit)
// @param command the task to execute 进行调度的线程
// @param delay the time from now to delay execution 延迟时间
// @param unit the time unit of the delay parameter 时间单位(毫秒 MILLISECONDS 、微妙等)
// 发送心跳包
BeatReactor.this.executorService.schedule(BeatReactor.this.new BeatTask(beatInfo), 0L, TimeUnit.MILLISECONDS);
LogUtils.LOG.info("BEAT", "send beat to server: " + beatInfo.toString());
}
} catch (Exception var4) {
LogUtils.LOG.error("CLIENT-BEAT", "Exception while scheduling beat.", var4);
}
}
}
}
BeatReactor 在创建时启动了一个定时任务ScheduledExecutorService,
该定时任务主要工作就是不停的通过http请求发送心跳数据到Nacos服务端。
a、向Nacos集群的随机一个节点的/v1/ns/api/clientBeat路径发送HTTP GET请求;
b、从json响应中取出clientBeatInterval字段值更新BeatReactor的clientBeatInterval属性值。
- 8、
NamingProxy 类
源码分析 实现服务注册。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.alibaba.nacos.client.naming.net;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import com.alibaba.nacos.client.naming.net.HttpClient.HttpResult;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.alibaba.nacos.client.naming.utils.IoUtils;
import com.alibaba.nacos.client.naming.utils.LogUtils;
import com.alibaba.nacos.client.naming.utils.StringUtils;
import com.alibaba.nacos.common.util.UuidUtil;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
public class NamingProxy {
private static final int DEFAULT_SERVER_PORT = 8848;
private String namespace;
private String endpoint;
private String nacosDomain;
private List<String> serverList;
private List<String> serversFromEndpoint = new ArrayList();
private long lastSrvRefTime = 0L;
private long vipSrvRefInterMillis;
private ScheduledExecutorService executorService;
public NamingProxy(String namespace, String endpoint, String serverList) {
this.vipSrvRefInterMillis = TimeUnit.SECONDS.toMillis(30L);
this.namespace = namespace;
this.endpoint = endpoint;
if (StringUtils.isNotEmpty(serverList)) {
this.serverList = Arrays.asList(serverList.split(","));
if (this.serverList.size() == 1) {
this.nacosDomain = serverList;
}
}
this.executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.client.naming.serverlist.updater");
t.setDaemon(true);
return t;
}
});
this.executorService.scheduleWithFixedDelay(new Runnable() {
public void run() {
NamingProxy.this.refreshSrvIfNeed();
}
}, 0L, this.vipSrvRefInterMillis, TimeUnit.MILLISECONDS);
this.refreshSrvIfNeed();
}
// 此时接上面第 6 步 ,服务注册实现
public void registerService(String serviceName, Instance instance) throws NacosException {
LogUtils.LOG.info("REGISTER-SERVICE", "registering service " + serviceName + " with instance:" + instance);
Map<String, String> params = new HashMap(8);
params.put("tenant", this.namespace);
params.put("ip", instance.getIp());
params.put("port", String.valueOf(instance.getPort()));
params.put("weight", String.valueOf(instance.getWeight()));
params.put("enable", String.valueOf(instance.isEnabled()));
params.put("healthy", String.valueOf(instance.isHealthy()));
params.put("metadata", JSON.toJSONString(instance.getMetadata()));
params.put("serviceName", serviceName);
params.put("clusterName", instance.getClusterName());
this.reqAPI("/nacos/v1/ns/instance", params, (String)"PUT");
}
// ……
// 该类的源码在这里被省略部分方法,如需了解该类完整源码,可查看相关文档。
// ……
}
.