nacos原理--nacos注册原理分析

1. nacos使用
引入pom文件
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>${官方版本号}</version>
</dependency>

在启动类上添加@EnableDiscoveryClient

@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudConfigClientApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringCloudConfigClientApplication.class, args);
   }
}

并添加配置文件

spring.cloud.nacos.discovery.server-addr=http://localhost:8848
2. nacos注册原理
查看spring-cloud-starter-alibaba-nacos-discovery包中spring.factories类能够看到如下源码:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,\
  com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,\
  com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\
  com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,\
  com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\
  com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\
  com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
  com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration

 其中关键类:NacosServiceRegistryAutoConfiguration

@Bean
public NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
   return new NacosServiceRegistry(nacosDiscoveryProperties);
}

@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosRegistration nacosRegistration(NacosDiscoveryProperties nacosDiscoveryProperties,ApplicationContext context) {
   return new NacosRegistration(nacosDiscoveryProperties, context);
}

@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
      NacosServiceRegistry registry,AutoServiceRegistrationProperties autoServiceRegistrationProperties,NacosRegistration registration) {
   return new NacosAutoServiceRegistration(registry,
         autoServiceRegistrationProperties, registration);
}

NacosServiceRegistry和NacosRegistration都将作为参数注册到NacosAutoServiceRegistration,那么NacosAutoServiceRegistration是个核心类,同时能够看到继承的接口AbstractAutoServiceRegistration也继承了ApplicationListener<WebServerInitializedEvent>,那么就是当Web程序初始化完成后调用:

// web程序初始化完成后发送消息,本类监听到事件后执行
public void onApplicationEvent(WebServerInitializedEvent event) {
    this.bind(event);
}

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());
        this.start();
    }
}

public void start() {
    if (!this.isEnabled()) {
        //...
    } else {
        // 用于是否已经注册了
        if (!this.running.get()) {
            this.context.publishEvent(new InstancePreRegisteredEvent(this, this.getRegistration()));
            // 关键方法,即本方法就是将服务注册到nacos中
            this.register();
            if (this.shouldRegisterManagement()) {
                this.registerManagement();
            }

            this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));
            this.running.compareAndSet(false, true);
        }

    }
}
// 此处就调用NacosServiceRegistry中register方法
protected void register() {
    this.serviceRegistry.register(this.getRegistration());
}

接下啦是NacosServiceRegistry类register方法

public void register(Registration registration) {
    // 服务ID为空直接退出
   if (StringUtils.isEmpty(registration.getServiceId())) {
      return;
   }
   String serviceId = registration.getServiceId();
   String group = nacosDiscoveryProperties.getGroup();
    // 生成Instance
   Instance instance = getNacosInstanceFromRegistration(registration);

   try {
       // 调用http请求注册
      namingService.registerInstance(serviceId, group, instance);
   }
}

public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    if (instance.isEphemeral()) {
        // 如果是临时实例,需要通过心跳的方式保持
        BeatInfo beatInfo = new BeatInfo();
        beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));
        beatInfo.setIp(instance.getIp());
        beatInfo.setPort(instance.getPort());
        beatInfo.setCluster(instance.getClusterName());
        beatInfo.setWeight(instance.getWeight());
        beatInfo.setMetadata(instance.getMetadata());
        beatInfo.setScheduled(false);
        beatInfo.setPeriod(instance.getInstanceHeartBeatInterval());
        // 定时任务,每隔一段时间发送短信
        this.beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);
    }
    // 注册
    this.serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);
}
// 发送心跳
public void addBeatInfo(String serviceName, BeatInfo beatInfo) {
    // ...省略
    this.dom2Beat.put(key, beatInfo);
    // 定时任务
    this.executorService.schedule(new BeatReactor.BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS);
    MetricsMonitor.getDom2BeatSizeMonitor().set((double)this.dom2Beat.size());
}

// 参数拼接调用http请求
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
    LogUtils.NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}", new Object[]{this.namespaceId, serviceName, instance});
    Map<String, String> params = new HashMap(9);
    params.put("namespaceId", this.namespaceId);
    params.put("serviceName", serviceName);
    params.put("groupName", groupName);
    params.put("clusterName", instance.getClusterName());
    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("ephemeral", String.valueOf(instance.isEphemeral()));
    params.put("metadata", JSON.toJSONString(instance.getMetadata()));
    this.reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, "POST");
}

 总结:nacos客户端注册原理简单,通过找到Spring注解的源码,并顺着往下读,基本能够看到Nacos通过http的方式将生产的Instance发送客户端。如果是临时节点,需要通过心跳的方式维持,而心跳式通过定时任务的方式间隔的发送来保持。

posted @ 2021-06-06 09:34  冰魄秋雨  阅读(384)  评论(0编辑  收藏  举报