Eureka源码--客户端初始化

238 阅读2分钟

Eureka客户端源码-客户端初始化

Eureka源码阅读大概流程如下,先找到依赖jar文件,最终到DiscoveryClient 该类是客户端的核心类

image-20211105161757561.png

初始化DiscoveryClient 这里把DiscoveryClient分4个部分进行描述

初始化执行器

    private final ScheduledExecutorService scheduler;
    private final ThreadPoolExecutor heartbeatExecutor;
    private final ThreadPoolExecutor cacheRefreshExecutor;
      //初始化调度器,2个核心线程
      scheduler = Executors.newScheduledThreadPool(2,
                                                   new ThreadFactoryBuilder().
                                                   setNameFormat("DiscoveryClient-%d").
                                                   setDaemon(true).build());
      //心跳执行器,核心线程1,最大线程可以配置,
      heartbeatExecutor = new ThreadPoolExecutor(1, 
                                                 clientConfig.getHeartbeatExecutorThreadPoolSize(), 
                                                 0, TimeUnit.SECONDS,
                                                 new SynchronousQueue<Runnable>(), 
                                                 new ThreadFactoryBuilder().
                                                 setNameFormat("DiscoveryClient-HeartbeatExecutor-%d").
                                                 setDaemon(true).build()
      ); 
      //本地注册表缓存刷新执行器
      cacheRefreshExecutor = new ThreadPoolExecutor(1, 
                                                    clientConfig.getCacheRefreshExecutorThreadPoolSize(), 
                                                    0, TimeUnit.SECONDS,
                                                    new SynchronousQueue<Runnable>(),
                                                    new ThreadFactoryBuilder().
                                                    setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d").
                                                    setDaemon(true).build()
      ); 
  • 获取注册信息前提配置允许从EurekaServer获取注册表,默认是true
    //是否从EurekaServer获取注册信息
    if (clientConfig.shouldFetchRegistry()) {
      try {
        //是否全量获取注册信息(传入的参数是false,表示不强制进行全量获取)
        boolean primaryFetchRegistryResult = fetchRegistry(false);
        boolean backupFetchRegistryResult = true;
        //上面获取失败的时候才会执行fetchRegistryFromBackup()
        //fetchRegistryFromBackup(从其他EuerkaServer或者本地进行获取注册表)
        if (!primaryFetchRegistryResult && !fetchRegistryFromBackup()) {
          backupFetchRegistryResult = false;
        }
        //上面两种方式都没有获取到,并且配置了 「强制在初始化时获取注册信息」为true,则抛出异常,默认是false
        if (!primaryFetchRegistryResult && !backupFetchRegistryResult && clientConfig.shouldEnforceFetchRegistryAtInit()) {
          throw new IllegalStateException("Fetch registry error at startup. Initial fetch failed.");
        }
      } catch (Throwable th) {
      }
    }

服务注册

    //是否注册到Eureka 并且 在初始化的时候强制进行注册
    if (clientConfig.shouldRegisterWithEureka() && clientConfig.shouldEnforceRegistrationAtInit()) {
        //执行注册流程
        if (!register() ) {
          throw new IllegalStateException("Registration error at startup. Invalid server response.");
        }
    }

初始各种task

    initScheduledTasks();
    private void initScheduledTasks() {
      //如果需要从EurekaServer获取注册信息
      if (clientConfig.shouldFetchRegistry()) {
        //配置注解参考上面的EurekaClientConfig配置注解
        int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();
        int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
        //本地缓存task
        cacheRefreshTask = new TimedSupervisorTask("cacheRefresh", 
                                                   scheduler, cacheRefreshExecutor,       
                                                   registryFetchIntervalSeconds, TimeUnit.SECONDS,
                                                   expBackOffBound, new CacheRefreshThread());
        //调度本地缓存task
        scheduler.schedule(cacheRefreshTask, registryFetchIntervalSeconds, TimeUnit.SECONDS);
      }
      
      //如果需要注册到注册表
      if (clientConfig.shouldRegisterWithEureka()) {
        int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
        int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
        // 心跳Task
        heartbeatTask = new TimedSupervisorTask("heartbeat", 
                                                scheduler, heartbeatExecutor,
                                                renewalIntervalInSecs, TimeUnit.SECONDS, 
                                                expBackOffBound, new HeartbeatThread());
        //开始调度心跳task
        scheduler.schedule(heartbeatTask, renewalIntervalInSecs, TimeUnit.SECONDS);
        // InstanceInfo复制器,实现Runnable接口,主要是更新本地的instanceInfo到EurekaServer上
        instanceInfoReplicator = new InstanceInfoReplicator(this, instanceInfo, 
          clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2); // burstSize
        //状态变化监听器
        statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
          @Override
          public String getId() {
            return "statusChangeListener";
          }
          @Override
          public void notify(StatusChangeEvent statusChangeEvent) {
            if (InstanceStatus.DOWN == statusChangeEvent.getStatus() ||
                InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) {
            }
            //状态变化之后,进行instanceInfo更新
            instanceInfoReplicator.onDemandUpdate();
          }
        };
        //如果设置为true,本地InstanceInfo状态边个了,会注册或者更新到EurekaServer上
        if (clientConfig.shouldOnDemandUpdateStatusChange()) {
          applicationInfoManager.registerStatusChangeListener(statusChangeListener);
        }
        //启动,开始任务调度,调度的任务就是自身(instanceInfoReplicator) 主要是更新本地的InstanceInfo
        instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
      }
    }

总结

  • 初始化EurekaClientConfig:主要是客户端的相关配置信息
  • 初始化DiscoveryClient 核心类主要是用于获取注册信息、续约、更新、取消等操作
  • 初始化并启动 本地注册表刷新定时任务、心跳定时任务、instance配置更新定时任务、
  • 并根据配置是否发起注册流程