02. Nacos客户端-服务发现原理

Nacos 客户端启动时自动拉取服务列表

在自动注册时说过,在springBoot项目启动时,会加载nacos相关的spring.factories文件,而自动发现最关键的类在 NacosDiscoveryClientConfiguration 在自动配置类中,名为NacosWatch,下图可以看出,其也会被Spring容器加载。

image-20231126141932690

NacosWatch 实现了 SmartLifeCycle 接口,这是 spring 提供的扩展点之一,IOC容器在初始化结束时会调用所有容器中 SmartLifecycle 实现类的 start 方法

image-20231126143839072

Start 方法中的 namingService.subscribe 方法里会从服务端拉取注册表

@Override
public void start() {
   
   if (this.running.compareAndSet(false, true)) {
   
      // 创建一个监听NamingEvent事件的监听器,加入到listenerMap中
      EventListener eventListener = listenerMap.computeIfAbsent(buildKey(),
            event -> new EventListener() {
   
               @Override
               public void onEvent(Event event) {
   
                  if (event instanceof NamingEvent) {
   
                     List<Instance> instances = ((NamingEvent) event)
                           .getInstances();
                     Optional<Instance> instanceOptional = selectCurrentInstance(
                           instances);
                     instanceOptional.ifPresent(currentInstance -> {
   
                        resetIfNeeded(currentInstance);
                     });
                  }
               }
            });

      // 获取namingService
      NamingService namingService = nacosServiceManager
            .getNamingService(properties.getNacosProperties());
      try {
   
         // 这里面会从服务端拉取一次注册表
         namingService.subscribe(properties.getService(), properties.getGroup(),
               Arrays.asList(properties.getClusterName()), eventListener);
      }
      catch (Exception e) {
   
         log.error("namingService subscribe failed, properties:{}", properties, e);
      }

      this.watchFuture = this.taskScheduler.scheduleWithFixedDelay(
            this::nacosServicesWatch, this.properties.getWatchDelay());
   }
}

上面注册监听我们先不讲解,下面的 getServiceInfo 方法才是关键

image-20231126154508167

public ServiceInfo getServiceInfo(final String serviceName, final String clusters) {
   

    NAMING_LOGGER.debug("failover-mode: " + failoverReactor.isFailoverSwitch());
    String key = ServiceInfo.getKey(serviceName, clusters);
    if (failoverReactor.isFailoverSwitch()) {
   
        return failoverReactor.getService(key);
    }

    // 从缓存中获取该service@@cluster下的服务实例列表
    ServiceInfo serviceObj = getServiceInfo0(serviceName, clusters);

    if (null == serviceObj) {
   
        serviceObj = new ServiceInfo(serviceName, clusters);

        serviceInfoMap.put(serviceObj.getKey(), serviceObj);

        // 在多线程的情况下,为了避免太多线程同时在更新注册列表,往updatingMap设置一个值,但是还是不可避免有几个线程同时更新
        updatingMap.put(serviceName, new Object());
        // 里面会调用server端接口查询服务列表,并更新到serviceInfoMap
        updateServiceNow(serviceName, clusters);
        updatingMap.remove(serviceName);

    } else if (updatingMap.containsKey(serviceName)) {
   

        if (UPDATE_HOLD_INTERVAL > 0) {
   
            // hold a moment waiting for update finish
            synchronized (serviceObj) {
   
                try {
   
                    serviceObj.wait(UPDATE_HOLD_INTERVAL);
                } catch (InterruptedException e) {
   
                    NAMING_LOGGER
                            .error("[getServiceInfo] serviceName:" + serviceName + ", clusters:" +</
  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值