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服务端中,客户端的代码就是如此,还是挺简单的,我们下一篇就会带大家走进服务端的代码。

(0)

相关推荐

  • Nacos概述

    1.1      Nacos是什么 Nacos是构建以"服务"为中心的现代应用架构(例如微服务范式.云原生范式)的服务基础设施,致力于微服务的发现.管理和信息配置,能帮助开发者快速 ...

  • 设计模式(一)——Java单例模式(代码+源码分析)

    设计模式(一)——Java单例模式(代码+源码分析)

  • 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)

    设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)

  • Qt update刷新之源码分析(一)

    在做GUI开发时,要让控件刷新,会调用update函数:那么在调用了update函数后,Qt究竟基于什么原理.执行了什么代码使得屏幕上有变化?本文就带大家来探究探究其内部源码. Qt手册中关于QWid ...

  • 【老孟Flutter】源码分析系列之InheritedWidget

    老孟导读:这是2021年源码系列的第一篇文章,其实源码系列的文章不是特别受欢迎,一个原因是原理性的知识非常枯燥,我自己看源码的时候特别有感触,二是想把源码分析讲的通俗易懂非常困难,自己明白 和 让别人 ...

  • Wifi模块—源码分析Wifi热点的开启(Android P)

    一 前言 Android使用一个修改版wpa_supplicant作为daemon来控制WIFI,它是一个安全中间件,代码位于external/wpa_supplicant,为各种无线网卡提供统一的安 ...

  • 协程库 libtask 源码分析

    本文在公司内网有不错的反响,但不同于传统的前端技术文章,所以阅读起来可能有点晦涩. 假设读者已经了解了协程的概念.实现协程的底层技术支持,基于底层基础,我们来看看如何实现协程以及协程的应用. 什么是 ...

  • 线程池ThreadPoolExecutor源码分析,看这一篇就够了

    前言 多线程是我们日常工作中很少能接触到的技术,但是面试的时候100%会被问到,万一工作中用到了基本不会,本篇咱们就来深入分析线程池的实现类ThreadPoolExecutor. 1.构造方法 构造方 ...

  • DRF认证流程及源码分析

    认证 前言 用户验证用户是否合法登陆. 部分内容在DRF视图的使用及源码流程分析讲解,建议先看讲解视图的这篇文章. 使用流程 认证使用的方法流程如下: 自定义认证类,继承BaseAuthenticat ...

  • Java教程——LinkedHashMap源码分析

    大多企业级项目开发都会选择Java,这使得我们Java工程师们都是"全能型"人才,这使得项目经验成为了Java人面试的重头戏之一. 简介 LinkedHashMap内部维护了一个双 ...