欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringCloud輪詢拉取注冊表與服務(wù)發(fā)現(xiàn)流程詳解

 更新時間:2022年11月23日 11:02:13   作者:卡布奇諾-海晨  
這篇文章主要介紹了SpringCloud輪詢拉取注冊表與服務(wù)發(fā)現(xiàn),現(xiàn)在很多創(chuàng)業(yè)公司都開始往springcloud靠了,可能是由于文檔和組件比較豐富的原因吧,畢竟是一款目前來說比較完善的微服務(wù)架構(gòu)

一、前言

上一篇我們討論了關(guān)于周期性任務(wù)的一些應(yīng)用等,本篇文章我們來探究一下這些內(nèi)容:周期性刷新注冊表?全量拉取注冊表還是增量拉取注冊表、更新本地緩存?服務(wù)發(fā)現(xiàn)的入口、獲取本地服務(wù)列表?

二、輪詢拉取注冊表

1、構(gòu)造初始化

同樣是在Spring容器初始化的過程中初始化的,基于SpringBoot自動裝配集成。上一節(jié)也講了一部分,這里補充:

@Singleton
public class DiscoveryClient implements EurekaClient {
    ....省略n行代碼......
    private final ScheduledExecutorService scheduler;
    // additional executors for supervised subtasks監(jiān)督子任務(wù)的附加執(zhí)行器
    private final ThreadPoolExecutor heartbeatExecutor;
    private final ThreadPoolExecutor cacheRefreshExecutor;
    private TimedSupervisorTask cacheRefreshTask;
    private TimedSupervisorTask heartbeatTask;
    ....省略n行代碼......
    // Spring容器初始化時候調(diào)用
    public DiscoveryClient(ApplicationInfoManager applicationInfoManager,
                           final EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args) {
        // 調(diào)用下面重載方法
        this(applicationInfoManager, config, args, ResolverUtils::randomize);
    }
    public DiscoveryClient(ApplicationInfoManager applicationInfoManager,
                           final EurekaClientConfig config,
                           AbstractDiscoveryClientOptionalArgs args, EndpointRandomizer randomizer) {
        this(applicationInfoManager, config, args, new Provider<BackupRegistry>() {
        ....省略n行代碼......
    }
    @Inject
    DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config,
                    AbstractDiscoveryClientOptionalArgs args,
                    Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer) {
        try {
            // default size of 2 - 1 each for heartbeat and cacheRefresh心跳和緩存刷新的默認(rèn)大小分別為2-1
            scheduler = Executors.newScheduledThreadPool(2,
                    new ThreadFactoryBuilder()
                            .setNameFormat("DiscoveryClient-%d")
                            .setDaemon(true)
                            .build());
            // 心跳執(zhí)行者
            heartbeatExecutor = new ThreadPoolExecutor(
                    1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
                    new SynchronousQueue<Runnable>(),
                    new ThreadFactoryBuilder()
                            .setNameFormat("DiscoveryClient-HeartbeatExecutor-%d")
                            .setDaemon(true)
                            .build()
            );  // use direct handoff
            // 緩存刷新執(zhí)行者
            cacheRefreshExecutor = new ThreadPoolExecutor(
                    1, clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
                    new SynchronousQueue<Runnable>(),
                    new ThreadFactoryBuilder()
                            .setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d")
                            .setDaemon(true)
                            .build()
            );  // use direct handoff
            // 初始化通信封裝類
            eurekaTransport = new EurekaTransport();
        ....省略n行代碼......
        } catch (Throwable e) {
            throw new RuntimeException("Failed to initialize DiscoveryClient!", e);
        }
        // 默認(rèn)true,可更改配置不建議
        if (clientConfig.shouldFetchRegistry()) {
            try {// 初始化注冊表
                boolean primaryFetchRegistryResult = fetchRegistry(false);
                // 下面主要打印失敗日志,初始化時控制臺可見是處理成功的
                if (!primaryFetchRegistryResult) {
                    // 從主服務(wù)器初始注冊表提取失敗
                    logger.info("Initial registry fetch from primary servers failed");
                }
                boolean backupFetchRegistryResult = true;
                if (!primaryFetchRegistryResult && !fetchRegistryFromBackup()) {
                    // 如果所有的eureka服務(wù)器網(wǎng)址都無法訪問,從備份注冊表中獲取注冊表信息也失敗。
                    backupFetchRegistryResult = false;
                    // 從備份服務(wù)器初始注冊表提取失敗
                    logger.info("Initial registry fetch from backup servers failed");
                }
                if (!primaryFetchRegistryResult && !backupFetchRegistryResult && clientConfig.shouldEnforceFetchRegistryAtInit()) {
                    // 在啟動時獲取注冊表錯誤。初始獲取失敗。
                    throw new IllegalStateException("Fetch registry error at startup. Initial fetch failed.");
                }
            } catch (Throwable th) {
                logger.error("Fetch registry error at startup: {}", th.getMessage());
                throw new IllegalStateException(th);
            }
        }
       ....省略n行代碼......
        // 最后,初始化調(diào)度任務(wù)(例如,集群解析器、 heartbeat、 instanceInfo replicator、 fetch
        initScheduledTasks();
      ....省略n行代碼......
    }

主要邏輯:

  • 初始化緩存刷新執(zhí)行器,用于周期性執(zhí)行任務(wù),下面繼續(xù)分析
  • 默認(rèn)需要刷新注冊表,默認(rèn)不使用全量拉取,但是初始化時使用下面2分析:會調(diào)用注冊中心完成注冊表初始化,返回是否刷新成功;如果從主服務(wù)器初始注冊表提取失敗打印日志;如果所有的eureka服務(wù)器網(wǎng)址都無法訪問,從備份注冊表中獲取注冊表信息也失敗打印日志;在啟動時獲取注冊表錯誤,拋異常。
  • 可見在2中沒有特殊原因的話,一般是使用全量拉取注冊表初始化成功了,否則的話拋異常

緩存刷新

大部分邏輯在前面的章節(jié)已經(jīng)分析,TimedSupervisorTask跟發(fā)送心跳服務(wù)續(xù)約邏輯是一樣的,這里補充刷新本地服務(wù)列表任務(wù)。

    private void initScheduledTasks() {
        // 默認(rèn)true,可更改配置不建議
        if (clientConfig.shouldFetchRegistry()) {
            // registry cache refresh timer注冊表緩存刷新計時器
            // 默認(rèn)30
            int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();
            int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
            cacheRefreshTask = new TimedSupervisorTask(
                    "cacheRefresh",
                    scheduler,
                    cacheRefreshExecutor,
                    registryFetchIntervalSeconds,
                    TimeUnit.SECONDS,
                    expBackOffBound,
                    new CacheRefreshThread()
            );
            scheduler.schedule(
                    cacheRefreshTask,
                    registryFetchIntervalSeconds, TimeUnit.SECONDS);
        }
        if (clientConfig.shouldRegisterWithEureka()) {
            /*  LeaseInfo:
                public static final int DEFAULT_LEASE_RENEWAL_INTERVAL = 30;
                // Client settings
                private int renewalIntervalInSecs = DEFAULT_LEASE_RENEWAL_INTERVAL;
             */
            // 默認(rèn)30
            int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
            int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
            logger.info("Starting heartbeat executor: " + "renew interval is: {}", renewalIntervalInSecs);
            // Heartbeat timer心跳任務(wù)
            heartbeatTask = new TimedSupervisorTask(
                    "heartbeat",
                    scheduler,
                    heartbeatExecutor,
                    renewalIntervalInSecs,
                    TimeUnit.SECONDS,
                    expBackOffBound,
                    new HeartbeatThread()
            );
            // 默認(rèn)的情況下會每隔30秒向注冊中心 (eureka.instance.lease-renewal-interval-in-seconds)發(fā)送一次心跳來進(jìn)行服務(wù)續(xù)約
            scheduler.schedule(
                    heartbeatTask,
                    renewalIntervalInSecs, TimeUnit.SECONDS);
            // InstanceInfo replicator實例信息復(fù)制任務(wù)
            instanceInfoReplicator = new InstanceInfoReplicator(
                    this,
                    instanceInfo,
                    clientConfig.getInstanceInfoReplicationIntervalSeconds(),
                    2); // burstSize
            // 狀態(tài)變更監(jiān)聽者
            statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
                @Override
                public String getId() {
                    return "statusChangeListener";
                }
                @Override
                public void notify(StatusChangeEvent statusChangeEvent) {
                    // Saw local status change event StatusChangeEvent [timestamp=1668595102513, current=UP, previous=STARTING]
                    logger.info("Saw local status change event {}", statusChangeEvent);
                    instanceInfoReplicator.onDemandUpdate();
                }
            };
            // 初始化狀態(tài)變更監(jiān)聽者
            if (clientConfig.shouldOnDemandUpdateStatusChange()) {
                applicationInfoManager.registerStatusChangeListener(statusChangeListener);
            }
            // 3.2 定時刷新服務(wù)實例信息和檢查應(yīng)用狀態(tài)的變化,在服務(wù)實例信息發(fā)生改變的情況下向server重新發(fā)起注冊
            instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
        } else {
            logger.info("Not registering with Eureka server per configuration");
        }
    }

主要邏輯:

默認(rèn)需要刷新注冊表,要達(dá)到服務(wù)高可用。

1)clientConfig.getRegistryFetchIntervalSeconds()獲取注冊表刷新時間,默認(rèn)30秒,可在配置文件更改;

2)初始化cacheRefreshTask為TimedSupervisorTask類型,跟心跳任務(wù)一樣處理邏輯,我們這節(jié)就只分析CacheRefreshThread刷新緩存邏輯,見3

2、刷新注冊表

    private boolean fetchRegistry(boolean forceFullRegistryFetch) {
        Stopwatch tracer = FETCH_REGISTRY_TIMER.start();
        try {
            // If the delta is disabled or if it is the first time, get all
            // applications如果 delta 被禁用或者是第一次,那么獲取所有的應(yīng)用程序
            Applications applications = getApplications();
            // shouldDisableDelta默認(rèn)false
            if (clientConfig.shouldDisableDelta()
                    || (!Strings.isNullOrEmpty(clientConfig.getRegistryRefreshSingleVipAddress()))
                    || forceFullRegistryFetch
                    || (applications == null)
                    || (applications.getRegisteredApplications().size() == 0)
                    || (applications.getVersion() == -1)) //Client application does not have latest library supporting delta
            {
                // 第一次
                logger.info("Disable delta property false: {}", clientConfig.shouldDisableDelta());
                logger.info("Single vip registry refresh property null: {}", clientConfig.getRegistryRefreshSingleVipAddress());
                logger.info("Force full registry fetch false: {}", forceFullRegistryFetch);
                logger.info("Application is null false: {}", (applications == null));
                logger.info("Registered Applications size is zero true: {}",
                        (applications.getRegisteredApplications().size() == 0));
                logger.info("Application version is -1true: {}", (applications.getVersion() == -1));
                // 全量拉取
                getAndStoreFullRegistry();
            } else {
                // 增量拉取
                getAndUpdateDelta(applications);
            }
            applications.setAppsHashCode(applications.getReconcileHashCode());
            logTotalInstances();
        } catch (Throwable e) {
            logger.info(PREFIX + "{} - was unable to refresh its cache! This periodic background refresh will be retried in {} seconds. status = {} stacktrace = {}",
                    appPathIdentifier, clientConfig.getRegistryFetchIntervalSeconds(), e.getMessage(), ExceptionUtils.getStackTrace(e));
            return false;
        } finally {
            if (tracer != null) {
                tracer.stop();
            }
        }
        // Notify about cache refresh before updating the instance remote status
        // 在更新實例遠(yuǎn)程狀態(tài)之前通知緩存刷新
        onCacheRefreshed();
        // Update remote status based on refreshed data held in the cache
        // 根據(jù)緩存中保存的刷新數(shù)據(jù)更新遠(yuǎn)程狀態(tài)
        updateInstanceRemoteStatus();
        // registry was fetched successfully, so return true
        return true;
    }

主要邏輯:

  • 由上面的1.1可見狀態(tài)變更監(jiān)聽者還沒有初始化,從前面的文章也知道它的作用完成服務(wù)注冊,故這里從本地獲取應(yīng)用就為空。所以先打印下日志,調(diào)用全量拉取注冊表方法,下面分析。軌跡跟蹤對象非空,關(guān)閉。
  • 在更新實例遠(yuǎn)程狀態(tài)之前通知緩存刷新
  • 根據(jù)緩存中保存的刷新數(shù)據(jù)更新遠(yuǎn)程狀態(tài)

全量拉取注冊表

    private void getAndStoreFullRegistry() throws Throwable {
        long currentUpdateGeneration = fetchRegistryGeneration.get();
        // 從 eureka 服務(wù)器上獲取所有實例注冊信息
        logger.info("Getting all instance registry info from the eureka server");
        Applications apps = null;
        // RegistryRefreshSingleVipAddress默認(rèn)空
        EurekaHttpResponse<Applications> httpResponse = clientConfig.getRegistryRefreshSingleVipAddress() == null
                ? eurekaTransport.queryClient.getApplications(remoteRegionsRef.get())
                : eurekaTransport.queryClient.getVip(clientConfig.getRegistryRefreshSingleVipAddress(), remoteRegionsRef.get());
        // 響應(yīng)成功獲取應(yīng)用
        if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
            apps = httpResponse.getEntity();
        }
        // 200
        logger.info("The response status is {}", httpResponse.getStatusCode());
        if (apps == null) {
            logger.error("The application is null for some reason. Not storing this information");
        } else if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)) {
            // 緩存到本地
            localRegionApps.set(this.filterAndShuffle(apps));
            // 如:UP_1_
            logger.debug("Got full registry with apps hashcode {}", apps.getAppsHashCode());
        } else {
            logger.warn("Not updating applications as another thread is updating it already");
        }
    }

主要邏輯:

  • RegistryRefreshSingleVipAddress默認(rèn)空,故調(diào)用eurekaTransport.queryClient.getApplications(remoteRegionsRef.get())請求注冊中心
  • 響應(yīng)成功獲取應(yīng)用
  • 如果應(yīng)用apps空則打印下日志;一般CAS成功,在篩選僅具有 UP 狀態(tài)的實例的應(yīng)用程序并對它們進(jìn)行洗牌之后獲取應(yīng)用程序,緩存到本地localRegionApps(AtomicReference<Applications>類型);否則打印下日志

3、緩存刷新任務(wù)

    class CacheRefreshThread implements Runnable {
        @Override
        public void run() {
            refreshRegistry();
        }
    }
    @VisibleForTesting
    void refreshRegistry() {
        try {
            boolean isFetchingRemoteRegionRegistries = isFetchingRemoteRegionRegistries();
            boolean remoteRegionsModified = false;
            // This makes sure that a dynamic change to remote regions to fetch is honored.
            // 這可以確保對要獲取的遠(yuǎn)程區(qū)域的動態(tài)更改得到遵守。
            // 默認(rèn)null
            String latestRemoteRegions = clientConfig.fetchRegistryForRemoteRegions();
            if (null != latestRemoteRegions) {
                String currentRemoteRegions = remoteRegionsToFetch.get();
                if (!latestRemoteRegions.equals(currentRemoteRegions)) {
                    // Both remoteRegionsToFetch and AzToRegionMapper.regionsToFetch need to be in sync
                    // RemoteRegionsToFetch 和 AzToRegionMapper.regionsToFetch 都需要同步
                    synchronized (instanceRegionChecker.getAzToRegionMapper()) {
                        // CAS
                        if (remoteRegionsToFetch.compareAndSet(currentRemoteRegions, latestRemoteRegions)) {
                            String[] remoteRegions = latestRemoteRegions.split(",");
                            remoteRegionsRef.set(remoteRegions);
                            instanceRegionChecker.getAzToRegionMapper().setRegionsToFetch(remoteRegions);
                            remoteRegionsModified = true;
                        } else {
                            // 并發(fā)獲取修改的遠(yuǎn)程區(qū)域,忽略從{}到{}的更改
                            logger.info("Remote regions to fetch modified concurrently," +
                                    " ignoring change from {} to {}", currentRemoteRegions, latestRemoteRegions);
                        }
                    }
                } else {
                    // Just refresh mapping to reflect any DNS/Property change
                    // 只需刷新映射以反映任何 DNS/屬性更改
                    instanceRegionChecker.getAzToRegionMapper().refreshMapping();
                }
            }
            // 刷新注冊表
            boolean success = fetchRegistry(remoteRegionsModified);
            if (success) {
                registrySize = localRegionApps.get().size();
                lastSuccessfulRegistryFetchTimestamp = System.currentTimeMillis();
            }
            if (logger.isDebugEnabled()) {
                StringBuilder allAppsHashCodes = new StringBuilder();
                allAppsHashCodes.append("Local region apps hashcode: ");
                allAppsHashCodes.append(localRegionApps.get().getAppsHashCode());
                allAppsHashCodes.append(", is fetching remote regions? ");
                allAppsHashCodes.append(isFetchingRemoteRegionRegistries);
                for (Map.Entry<String, Applications> entry : remoteRegionVsApps.entrySet()) {
                    allAppsHashCodes.append(", Remote region: ");
                    allAppsHashCodes.append(entry.getKey());
                    allAppsHashCodes.append(" , apps hashcode: ");
                    allAppsHashCodes.append(entry.getValue().getAppsHashCode());
                }
                logger.debug("Completed cache refresh task for discovery. All Apps hash code is {} ",
                        allAppsHashCodes);
            }
        } catch (Throwable e) {
            logger.error("Cannot fetch registry from server", e);
        }
    }

CacheRefreshThread 實現(xiàn)了Runnable接口,但是run()中任務(wù)邏輯封裝了出去,在refreshRegistry()中處理。在2中分析了初始化時已經(jīng)使用全量拉取注冊表并緩存應(yīng)用到本地localRegionApps,那么這里使用延遲任務(wù)處理的話就會執(zhí)行增量拉取邏輯了,在下面4分析

4、增量拉取注冊表

    private void getAndUpdateDelta(Applications applications) throws Throwable {
        long currentUpdateGeneration = fetchRegistryGeneration.get();
        Applications delta = null;
        // 增量查詢獲取
        EurekaHttpResponse<Applications> httpResponse = eurekaTransport.queryClient.getDelta(remoteRegionsRef.get());
        // 響應(yīng)成功
        if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
            delta = httpResponse.getEntity();
        }
        if (delta == null) {
            // 服務(wù)器不允許應(yīng)用delta修訂,因為它不安全。因此得到了完整的登記表,即轉(zhuǎn)換為全量拉取
            logger.warn("The server does not allow the delta revision to be applied because it is not safe. "
                    + "Hence got the full registry.");
            getAndStoreFullRegistry();
        } else if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)) {
            // CAS成功
            logger.debug("Got delta update with apps hashcode {}", delta.getAppsHashCode());
            String reconcileHashCode = "";
            if (fetchRegistryUpdateLock.tryLock()) {
                // 加鎖成功
                try {
                    updateDelta(delta);
                    reconcileHashCode = getReconcileHashCode(applications);
                } finally {
                    fetchRegistryUpdateLock.unlock();
                }
            } else {
                logger.warn("Cannot acquire update lock, aborting getAndUpdateDelta");
            }
            // There is a diff in number of instances for some reason出于某種原因,數(shù)量有所不同
            if (!reconcileHashCode.equals(delta.getAppsHashCode()) || clientConfig.shouldLogDeltaDiff()) {
                reconcileAndLogDifference(delta, reconcileHashCode);  // this makes a remoteCall這個可以遠(yuǎn)程呼叫
            }
        } else {
            logger.warn("Not updating application delta as another thread is updating it already");
            logger.debug("Ignoring delta update with apps hashcode {}, as another thread is updating it already", delta.getAppsHashCode());
        }
    }

主要邏輯:

  • 增量查詢獲取,響應(yīng)成功獲取數(shù)據(jù)
  • CAS成功并且加鎖成功,將響應(yīng)結(jié)果更新到本地,然后釋放鎖

增量更新到本地緩存

    private void updateDelta(Applications delta) {
        int deltaCount = 0;
        for (Application app : delta.getRegisteredApplications()) {
            for (InstanceInfo instance : app.getInstances()) {
                // 從本地獲取,以便更新
                Applications applications = getApplications();
                String instanceRegion = instanceRegionChecker.getInstanceRegion(instance);
                if (!instanceRegionChecker.isLocalRegion(instanceRegion)) {
                    Applications remoteApps = remoteRegionVsApps.get(instanceRegion);
                    if (null == remoteApps) {
                        remoteApps = new Applications();
                        remoteRegionVsApps.put(instanceRegion, remoteApps);
                    }
                    applications = remoteApps;
                }
                ++deltaCount;
                if (ActionType.ADDED.equals(instance.getActionType())) {
                    Application existingApp = applications.getRegisteredApplications(instance.getAppName());
                    if (existingApp == null) {
                        applications.addApplication(app);
                    }
                    // 將實例{}添加到區(qū)域{}中的現(xiàn)有應(yīng)用程序
                    // ceam-config:8888,ceam-auth:8005,region null
                    logger.debug("Added instance {} to the existing apps in region {}", instance.getId(), instanceRegion);
                    // 即添加到Application的instancesMap
                    applications.getRegisteredApplications(instance.getAppName()).addInstance(instance);
                } else if (ActionType.MODIFIED.equals(instance.getActionType())) {
                    Application existingApp = applications.getRegisteredApplications(instance.getAppName());
                    if (existingApp == null) {
                        applications.addApplication(app);
                    }
                    // 修改現(xiàn)有應(yīng)用程序的實例{}
                    logger.debug("Modified instance {} to the existing apps ", instance.getId());
                    applications.getRegisteredApplications(instance.getAppName()).addInstance(instance);
                } else if (ActionType.DELETED.equals(instance.getActionType())) {
                    Application existingApp = applications.getRegisteredApplications(instance.getAppName());
                    if (existingApp != null) {
                        // 刪除現(xiàn)有應(yīng)用程序的實例{}
                        logger.debug("Deleted instance {} to the existing apps ", instance.getId());
                        existingApp.removeInstance(instance);
                        /*
                         * We find all instance list from application(The status of instance status is not only the status is UP but also other status)
                         * if instance list is empty, we remove the application.
                         * 我們從應(yīng)用程序中找到所有的實例列表(實例狀態(tài)的狀態(tài)不僅是狀態(tài)是 UP,
                         * 還有其他狀態(tài))如果實例列表為空,我們刪除應(yīng)用程序。
                         */
                        if (existingApp.getInstancesAsIsFromEureka().isEmpty()) {
                            applications.removeApplication(existingApp);
                        }
                    }
                }
            }
        }
        logger.debug("The total number of instances fetched by the delta processor : {}", deltaCount);
        getApplications().setVersion(delta.getVersion());
        // 對提供的實例進(jìn)行洗牌,以便它們不總是以相同的順序返回。
        getApplications().shuffleInstances(clientConfig.shouldFilterOnlyUpInstances());
        for (Applications applications : remoteRegionVsApps.values()) {
            applications.setVersion(delta.getVersion());
            // 對提供的實例進(jìn)行洗牌,以便它們不總是以相同的順序返回。
            applications.shuffleInstances(clientConfig.shouldFilterOnlyUpInstances());
        }
    }

主要邏輯:

  • 遍歷增量的應(yīng)用數(shù)據(jù),遍歷應(yīng)用中的實例
  • 從本地獲取應(yīng)用數(shù)據(jù),以便更新處理
  • 如果是ADDED,則將實例添加到區(qū)域中的現(xiàn)有應(yīng)用程序;如果是MODIFIED,則修改現(xiàn)有應(yīng)用程序的實例;如果是DELETED,則刪除現(xiàn)有應(yīng)用程序的實例,并且從應(yīng)用程序中找到所有的實例列表(實例狀態(tài)的狀態(tài)不僅是狀態(tài)是 UP,還有其他狀態(tài))如果實例列表為空,刪除應(yīng)用程序。
  • 對提供的實例進(jìn)行洗牌,以便它們不總是以相同的順序返回。

三、服務(wù)發(fā)現(xiàn)

1、客戶端獲取服務(wù)實例

	@Override
	public List<ServiceInstance> getInstances(String serviceId) {
		// 委托eurekaClient處理
		List<InstanceInfo> infos = this.eurekaClient.getInstancesByVipAddress(serviceId,
				false);
		List<ServiceInstance> instances = new ArrayList<>();
		for (InstanceInfo info : infos) {
			instances.add(new EurekaServiceInstance(info));
		}
		return instances;
	}

跟Nacos的入口是類似的,需要實現(xiàn)spring-cloud-commons的DiscoveryClient接口。這里EurekaDiscoveryClient會委托Eureka項目里面的EurekaClient處理,見下面2分析。然后將Instances列表轉(zhuǎn)換為spring-cloud-commons里面的ServiceInstance類型列表。

2、從本地列表獲取

    @Override
    public List<InstanceInfo> getInstancesByVipAddress(String vipAddress, boolean secure) {
        return getInstancesByVipAddress(vipAddress, secure, instanceRegionChecker.getLocalRegion());
    }
    @Override
    public List<InstanceInfo> getInstancesByVipAddress(String vipAddress, boolean secure,
                                                       @Nullable String region) {
        if (vipAddress == null) {
            throw new IllegalArgumentException(
                    "Supplied VIP Address cannot be null");
        }
        Applications applications;
        // 如果eureka:region:沒有指定,則使用默認(rèn)值且非空,即默認(rèn)使用默認(rèn)localRegion
        if (instanceRegionChecker.isLocalRegion(region)) {
            // 本地獲取
            applications = this.localRegionApps.get();
        } else {
            applications = remoteRegionVsApps.get(region);
            if (null == applications) {
                logger.debug("No applications are defined for region {}, so returning an empty instance list for vip "
                        + "address {}.", region, vipAddress);
                return Collections.emptyList();
            }
        }
        // secure默認(rèn)false
        if (!secure) {
            return applications.getInstancesByVirtualHostName(vipAddress);
        } else {
            return applications.getInstancesBySecureVirtualHostName(vipAddress);
        }
    }

主要邏輯:

  • 調(diào)用重載方法,vipAddress即serviceId,secure為false
  • 如果eureka:region:沒有指定,則使用默認(rèn)值且非空,即默認(rèn)使用默認(rèn)localRegion。從本地應(yīng)用獲取列表。
  • secure為false,獲取與虛擬主機名關(guān)聯(lián)的instance列表

到此這篇關(guān)于SpringCloud輪詢拉取注冊表與服務(wù)發(fā)現(xiàn)流程詳解的文章就介紹到這了,更多相關(guān)SpringCloud注冊表與服務(wù)發(fā)現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java web實現(xiàn)郵箱發(fā)送功能

    java web實現(xiàn)郵箱發(fā)送功能

    這篇文章主要為大家詳細(xì)介紹了java web實現(xiàn)郵箱發(fā)送功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • 詳解SpringBoot?JPA常用注解的使用方法

    詳解SpringBoot?JPA常用注解的使用方法

    這篇文章主要介紹了SpringBoot?JPA常用注解的使用方法,spring?boot作為當(dāng)前主流的技術(shù),來看看常用的注解怎么用,如果有錯誤的地方還請指正,需要的朋友可以參考下
    2023-03-03
  • javaweb實現(xiàn)文件上傳與下載功能

    javaweb實現(xiàn)文件上傳與下載功能

    這篇文章主要為大家詳細(xì)介紹了javaweb實現(xiàn)文件上傳與下載功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • Java System.currentTimeMillis()時間的單位轉(zhuǎn)換與計算方式案例詳解

    Java System.currentTimeMillis()時間的單位轉(zhuǎn)換與計算方式案例詳解

    這篇文章主要介紹了Java System.currentTimeMillis()時間的單位轉(zhuǎn)換與計算方式案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • SpringBoot+Quartz+數(shù)據(jù)庫存儲的完美集合

    SpringBoot+Quartz+數(shù)據(jù)庫存儲的完美集合

    這篇文章主要介紹了SpringBoot+Quartz+數(shù)據(jù)庫存儲的示例代碼,本文通過實例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • 關(guān)于Spring MVC同名參數(shù)綁定問題的解決方法

    關(guān)于Spring MVC同名參數(shù)綁定問題的解決方法

    Spring MVC中的參數(shù)綁定還是蠻重要的,最近在使用中遇到了同名參數(shù)綁定的問題,想著總結(jié)分享出來,下面這篇文章主要給大家介紹了關(guān)于Spring MVC同名參數(shù)綁定問題的解決方法,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-08-08
  • RocketMQ消息存儲文件的加載與恢復(fù)機制源碼分析

    RocketMQ消息存儲文件的加載與恢復(fù)機制源碼分析

    這篇文章主要介紹了RocketMQ源碼分析之消息存儲文件的加載與恢復(fù)機制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • java實現(xiàn)文件和base64相互轉(zhuǎn)換

    java實現(xiàn)文件和base64相互轉(zhuǎn)換

    這篇文章主要為大家詳細(xì)介紹了java如何實現(xiàn)文件和base64相互轉(zhuǎn)換,文中的示例代碼講解詳細(xì),具有一定的參考價值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11
  • spring boot 下支付寶的開箱既用環(huán)境

    spring boot 下支付寶的開箱既用環(huán)境

    這篇文章主要介紹了spring boot 下支付寶的開箱既用環(huán)境包括使用場景和使用技巧,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2017-10-10
  • 分析Java中為什么String不可變

    分析Java中為什么String不可變

    Java中為什么String是不可變性的。今天我們從多角度解析為什么Java把String做成不可變的。
    2021-06-06

最新評論