2020-12-26

Nacos(一)源码分析Nacos注册示例流程

nacos官方地址:https://nacos.io/zh-cn/

大家可以看一下nacos的中文手册以及官方源码,博主就不带领大家快速入门 了,官方文档中都有而且非常标准,比其他博客写的好多了并且还是实时更新的。

先看一下博主给大家画的流程图,掌握一下大概的基本流程,好理解,博主给大家讲源码:

https://www.processon.com/view/link/5f7e895be0b34d0711f65178

nacos最主要的功能就是服务注册及发现,那它到底是如何实现的呢?博主用的springboot开发的,所以直接就去找nacos的jar包下的spring.factories,这是每个要自动注入的服务jar的必备文件,我们来看一下

 

 

   里面有很多的自动配置类,我们只看一下NacosServiceRegistryAutoConfiguration,该类主要做的是服务注册的相关事宜,如果大家第一次看源码的话不知道该如何下手,最笨的方法就是一个一个看。总会找到的,最好要找名字看起来就像自己找的,因为这是阿里巴巴开发的,他们是有java开发规范的,要做到见名知意。

 1 /** 2   * @author xiaojing 3   * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> 4  */ 5  @Configuration(proxyBeanMethods = false) 6  @EnableConfigurationProperties 7  @ConditionalOnNacosDiscoveryEnabled 8  @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", 9    matchIfMissing = true)10  @AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,11    AutoServiceRegistrationAutoConfiguration.class,12    NacosDiscoveryAutoConfiguration.class })13  public class NacosServiceRegistryAutoConfiguration {14 15   @Bean16   public NacosServiceRegistry nacosServiceRegistry(17     NacosDiscoveryProperties nacosDiscoveryProperties) {18    return new NacosServiceRegistry(nacosDiscoveryProperties);19   }20 21   @Bean22   @ConditionalOnBean(AutoServiceRegistrationProperties.class)23   public NacosRegistration nacosRegistration(24     NacosDiscoveryProperties nacosDiscoveryProperties,25     ApplicationContext context) {26    return new NacosRegistration(nacosDiscoveryProperties, context);27   }28 29   @Bean30   @ConditionalOnBean(AutoServiceRegistrationProperties.class)31   public NacosAutoServiceRegistration nacosAutoServiceRegistration(32     NacosServiceRegistry registry,33     AutoServiceRegistrationProperties autoServiceRegistrationProperties,34     NacosRegistration registration) {35    //这里才是自动注入的类,我们需要进去看一下36    return new NacosAutoServiceRegistration(registry,37      autoServiceRegistrationProperties, registration);38   }39 40  }

 1 public class NacosAutoServiceRegistration 2   extends AbstractAutoServiceRegistration<Registration> { 3  4  private static final Logger log = LoggerFactory 5    .getLogger(NacosAutoServiceRegistration.class); 6  7  private NacosRegistration registration; 8  9  public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,10    AutoServiceRegistrationProperties autoServiceRegistrationProperties,11    NacosRegistration registration) {12   super(serviceRegistry, autoServiceRegistrationProperties);13   this.registration = registration;14  }15 16  @Deprecated17  public void setPort(int port) {18   getPort().set(port);19  }20 21  @Override22  protected NacosRegistration getRegistration() {23   if (this.registration.getPort() < 0 && this.getPort().get() > 0) {24    this.registration.setPort(this.getPort().get());25   }26   Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");27   return this.registration;28  }29 30  @Override31  protected NacosRegistration getManagementRegistration() {32   return null;33  }34 35  @Override36  protected void register() {37   if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {38    log.debug("Registration disabled.");39    return;40   }41   if (this.registration.getPort() < 0) {42    this.registration.setPort(getPort().get());43   }44   super.register();45  }46 47  @Override48  protected void registerManagement() {49   if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {50    return;51   }52   super.registerManagement();53 54  }55 56  @Override57  protected Object getConfiguration() {58   return this.registration.getNacosDiscoveryProperties();59  }60 61  @Override62  protected boolean isEnabled() {63   return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();64  }65 66  @Override67  @SuppressWarnings("deprecation")68  protected String getAppName() {69   String appName = registration.getNacosDiscoveryProperties().getService();70   return StringUtils.isEmpty(appName) ? super.getAppName() : appName;71  }72 73 }

看到这里,大家可能有点懵,我应该找那个方法呢?大家可以看一下构造器中,引用了父类,当我们看到父类的时候,发现父类实现了ApplicationListener,这个类大家不陌生,系统会自动执行其onApplicationEvent而正好我们的类实现了这个方法,最后我们发现了应该看register() 方法,大家可以来看看这个方法的实现
 1 @Override 2  public void register(Registration registration) { 3  4   if (StringUtils.isEmpty(registration.getServiceId())) { 5    log.warn("No service to register for nacos client..."); 6    return; 7   } 8   //看到这两个参数,大家看过nacos文档就知道这两个参数要干啥用了 9   String serviceId = registration.getServiceId();10   String group = nacosDiscoveryProperties.getGroup();11   //要发送的实例对象,具体的属性,大家可以看看这个方法12   Instance instance = getNacosInstanceFromRegistration(registration);13 14   try {15   //走这里,是真正的注册服务16    namingService.registerInstance(serviceId, group, instance);17    log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,18      instance.getIp(), instance.getPort());19   }20   catch (Exception e) {21    log.error("nacos registry, {} register failed...{},", serviceId,22      registration.toString(), e);23    // rethrow a RuntimeException if the registration is failed.24    // issue : https://github.com/alibaba/spring-cloud-alibaba/issues/113225    rethrowRuntimeException(e);26   }27  }

 1  @Override 2  public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException { 3   //是否是临时的,这个参数默认是临时实例,这个是临时或者是否持久很重要,先记住 4   if (instance.isEphemeral()) { 5    //填写各种心跳信息,毕竟服务需要往nacos发送心跳,nacos才能知道该服务是否还存活 6    BeatInfo beatInfo = new BeatInfo(); 7    beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName)); 8    beatInfo.setIp(instance.getIp()); 9    beatInfo.setPort(instance.getPort());10    beatInfo.setCluster(instance.getClusterName());11    beatInfo.setWeight(instance.getWeight());12    beatInfo.setMetadata(instance.getMetadata());13    beatInfo.setScheduled(false);14    beatInfo.setPeriod(instance.getInstanceHeartBeatInterval());15    //看一下客服端是如何发送心跳16    beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);17   }18   //注册服务19   serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);20  }

 1   @Override 2   public void run() { 3    if (beatInfo.isStopped()) { 4     return; 5    } 6    long nextTime = beatInfo.getPeriod(); 7    try { 8     //会调用nacos服务端的/instance/beat接口 9     JSONObject result = serverProxy.sendBeat(beatInfo, BeatReactor.this.lightBeatEnabled);10     long interval = result.getIntValue("clientBeatInterval");11     boolean lightBeatEnabled = false;12     if (result.containsKey(CommonParams.LIGHT_BEAT_ENABLED)) {13      lightBeatEnabled = result.getBooleanValue(CommonParams.LIGHT_BEAT_ENABLED);14     }15     BeatReactor.this.lightBeatEnabled = lightBeatEnabled;16     if (interval > 0) {17      nextTime = interval;18     }19     int code = NamingResponseCode.OK;20     if (result.containsKey(CommonParams.CODE)) {21      code = result.getIntValue(CommonParams.CODE);22     }23     //如果找不到服务,则进行注册服务24     if (code == NamingResponseCode.RESOURCE_NOT_FOUND) {25      Instance instance = new Instance();26      instance.setPort(beatInfo.getPort());27      instance.setIp(beatInfo.getIp());28      instance.setWeight(beatInfo.getWeight());29      instance.setMetadata(beatInfo.getMetadata());30      instance.setClusterName(beatInfo.getCluster());31      instance.setServiceName(beatInfo.getServiceName());32      instance.setInstanceId(instance.getInstanceId());33      instance.setEphemeral(true);34      try {35       //该方法封装好参数后,会调用/instance接口36       serverProxy.registerService(beatInfo.getServiceName(),37        NamingUtils.getGroupName(beatInfo.getServiceName()), instance);38      } catch (Exception ignore) {39      }40     }41    } catch (NacosException ne) {42     NAMING_LOGGER.error("[CLIENT-BEAT] failed to send beat: {}, code: {}, msg: {}",43      JSON.toJSONString(beatInfo), ne.getErrCode(), ne.getErrMsg());44 45    }46    //定时线程池不会一直循环进行调用,所以每次执行完之后会继续添加定时任务进行发送心跳47    executorService.schedule(new BeatTask(beatInfo), nextTime, TimeUnit.MILLISECONDS);48   }

  看完发送心跳的方法,我们该看注册服务的方法了:serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);其实就是发送心跳后,找不到服务时调用的/instance接口。

  到此,我们的服务就会注册到nacos服务端中,客户端的代码就是如此,还是挺简单的,我们下一篇就会带大家走进服务端的代码。


 









原文转载:http://www.shaoqun.com/a/504067.html

跨境电商:https://www.ikjzd.com/

bol:https://www.ikjzd.com/w/291

斑马物流:https://www.ikjzd.com/w/1316


nacos官方地址:https://nacos.io/zh-cn/大家可以看一下nacos的中文手册以及官方源码,博主就不带领大家快速入门了,官方文档中都有而且非常标准,比其他博客写的好多了并且还是实时更新的。先看一下博主给大家画的流程图,掌握一下大概的基本流程,好理解,博主给大家讲源码:https://www.processon.com/view/link/5f7e895be0b34d0711f
打折网:打折网
灰色清关:灰色清关
莆田妈祖:莆田妈祖
Facebook Ads Manager广告创建详解!及Facebook广告系列功能介绍、使用教程:Facebook Ads Manager广告创建详解!及Facebook广告系列功能介绍、使用教程
家得宝(HomeDepot):家得宝(HomeDepot)

No comments:

Post a Comment