zoukankan      html  css  js  c++  java
  • Eureka客户端启动源码分析

    一、@EnableDiscoveryClient

      eureka的客户端主要通过一个注解@EnableDiscoveryClient或@EnableEurekaClient开启的。

    共同点:都是能够让注册中心能够发现,扫描到该服务。

    不同点:@EnableEurekaClient只适用于Eureka作为注册中心,@EnableDiscoveryClient可以是其他注册中心,例如:eureka、consul、zookeeper等。

    不过在Edgware版本之后已经不推荐使用@EnableEurekaClient了,因为它已经变成了一个空的注解。并且就算不使用@EnableDiscoveryClient也是可以的,并不影响客户端的注册,只要我们添加了相应的客户端jar包即可,但是我们还是可以通过这个注解来决定是否注册到eureka服务端的。如果我们不想该服务注册到eureka server,只是想从注册中心拉取服务,我们只需要引导类上的注解改成@EnableDiscoveryClient(autoRegister = false)。

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    //导入了一个ImportSelector的实现类
    @Import(EnableDiscoveryClientImportSelector.class)
    public @interface EnableDiscoveryClient {
    
        boolean autoRegister() default true;
    
    }

    EnableDiscoveryClientImportSelector

    public class EnableDiscoveryClientImportSelector
            extends SpringFactoryImportSelector<EnableDiscoveryClient> {
    
        @Override
        public String[] selectImports(AnnotationMetadata metadata) {
            //调用父类的方法
            String[] imports = super.selectImports(metadata);
    
            AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                    metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
    
            boolean autoRegister = attributes.getBoolean("autoRegister");
            //注解的参数,默认true
            if (autoRegister) {
                List<String> importsList = new ArrayList<>(Arrays.asList(imports));
                //添加AutoServiceRegistrationConfiguration
                importsList.add(
                        "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
                imports = importsList.toArray(new String[0]);
            }
            else {
                Environment env = getEnvironment();
                if (ConfigurableEnvironment.class.isInstance(env)) {
                    ConfigurableEnvironment configEnv = (ConfigurableEnvironment) env;
                    LinkedHashMap<String, Object> map = new LinkedHashMap<>();
                    //设置属性不注册
                    map.put("spring.cloud.service-registry.auto-registration.enabled", false);
                    MapPropertySource propertySource = new MapPropertySource(
                            "springCloudDiscoveryClient", map);
                    configEnv.getPropertySources().addLast(propertySource);
                }
    
            }
    
            return imports;
        }
        
        ···
    }
    //使环境配置类生效
    @Configuration(proxyBeanMethods = false)
    @EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
    @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
            matchIfMissing = true)
    public class AutoServiceRegistrationConfiguration {
    
    }
    //环境配置类
    @ConfigurationProperties("spring.cloud.service-registry.auto-registration")
    public class AutoServiceRegistrationProperties {
    
        /** Whether service auto-registration is enabled. Defaults to true. */
        private boolean enabled = true;
    
        /** Whether to register the management as a service. Defaults to true. */
        private boolean registerManagement = true;
    
        /**
         * Whether startup fails if there is no AutoServiceRegistration. Defaults to false.
         */
        private boolean failFast = false;
    
        public boolean isEnabled() {
            return this.enabled;
        }
    
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    
        public boolean isRegisterManagement() {
            return this.registerManagement;
        }
    
        public void setRegisterManagement(boolean registerManagement) {
            this.registerManagement = registerManagement;
        }
    
        @Deprecated
        public boolean shouldRegisterManagement() {
            return this.registerManagement;
        }
    
        public boolean isFailFast() {
            return this.failFast;
        }
    
        public void setFailFast(boolean failFast) {
            this.failFast = failFast;
        }
    
    }

    @Import注解的用法这里就不要多说了,通过源码我们可以看到,通过注解可以控制是否实例化AutoServiceRegistrationConfiguration,进而控制是否进行服务的注册。

    二、自动装配

      打开客户端jar包下的spring.factories文件

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
    org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration,\
    org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
    org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
    org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,\
    org.springframework.cloud.netflix.eureka.reactive.EurekaReactiveDiscoveryClientConfiguration,\
    org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancerEurekaAutoConfiguration
    
    org.springframework.cloud.bootstrap.BootstrapConfiguration=\
    org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapConfiguration

    EurekaClientAutoConfiguration

    @Configuration(proxyBeanMethods = false)
    @EnableConfigurationProperties
    @ConditionalOnClass(EurekaClientConfig.class)
    @ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
    @ConditionalOnDiscoveryEnabled
    @AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class,
            CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
    @AutoConfigureAfter(name = {
            "org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration",
            "org.springframework.cloud.autoconfigure.RefreshAutoConfiguration",
            "org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration",
            "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" })
    public class EurekaClientAutoConfiguration {
    
        private ConfigurableEnvironment env;
    
        public EurekaClientAutoConfiguration(ConfigurableEnvironment env) {
            this.env = env;
        }
    
        ···
    
    }

    直接定位到EurekaClient的实例化

            @Bean(destroyMethod = "shutdown")
            @ConditionalOnMissingBean(value = EurekaClient.class,
                    search = SearchStrategy.CURRENT)
            public EurekaClient eurekaClient(ApplicationInfoManager manager,
                    EurekaClientConfig config) {
                return new CloudEurekaClient(manager, config, this.optionalArgs,
                        this.context);
            }

    通过CloudEurekaClient类包装了一下,追踪一下构造方法

    DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args,
                        Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer) {
            if (args != null) {
                this.healthCheckHandlerProvider = args.healthCheckHandlerProvider;
                this.healthCheckCallbackProvider = args.healthCheckCallbackProvider;
                this.eventListeners.addAll(args.getEventListeners());
                this.preRegistrationHandler = args.preRegistrationHandler;
            } else {
                this.healthCheckCallbackProvider = null;
                this.healthCheckHandlerProvider = null;
                this.preRegistrationHandler = null;
            }
            
            this.applicationInfoManager = applicationInfoManager;
            InstanceInfo myInfo = applicationInfoManager.getInfo();
    
            clientConfig = config;
            staticClientConfig = clientConfig;
            transportConfig = config.getTransportConfig();
            instanceInfo = myInfo;
            if (myInfo != null) {
                appPathIdentifier = instanceInfo.getAppName() + "/" + instanceInfo.getId();
            } else {
                logger.warn("Setting instanceInfo to a passed in null value");
            }
    
            this.backupRegistryProvider = backupRegistryProvider;
            this.endpointRandomizer = endpointRandomizer;
            this.urlRandomizer = new EndpointUtils.InstanceInfoBasedUrlRandomizer(instanceInfo);
            localRegionApps.set(new Applications());
    
            fetchRegistryGeneration = new AtomicLong(0);
    
            remoteRegionsToFetch = new AtomicReference<String>(clientConfig.fetchRegistryForRemoteRegions());
            remoteRegionsRef = new AtomicReference<>(remoteRegionsToFetch.get() == null ? null : remoteRegionsToFetch.get().split(","));
    
            //是否拉取服务端的已注册的服务,可以通过配置去除,eureka.client.fetch-registry=false
            if (config.shouldFetchRegistry()) {
                this.registryStalenessMonitor = new ThresholdLevelsMetric(this, METRIC_REGISTRY_PREFIX + "lastUpdateSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
            } else {
                this.registryStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
            }
            //是否向服务端注册,通过配置去除,eureka.client.register-with-eureka=false
            if (config.shouldRegisterWithEureka()) {
                this.heartbeatStalenessMonitor = new ThresholdLevelsMetric(this, METRIC_REGISTRATION_PREFIX + "lastHeartbeatSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
            } else {
                this.heartbeatStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
            }
    
            logger.info("Initializing Eureka in region {}", clientConfig.getRegion());
            
            //如果不注册,也不拉取服务端的其他微服务实例,相当于直接禁用了eureka
            //此时直接将一些属性信息置空,直接返回
            if (!config.shouldRegisterWithEureka() && !config.shouldFetchRegistry()) {
                logger.info("Client configured to neither register nor query for data.");
                scheduler = null;
                heartbeatExecutor = null;
                cacheRefreshExecutor = null;
                eurekaTransport = null;
                instanceRegionChecker = new InstanceRegionChecker(new PropertyBasedAzToRegionMapper(config), clientConfig.getRegion());
                DiscoveryManager.getInstance().setDiscoveryClient(this);
                DiscoveryManager.getInstance().setEurekaClientConfig(config);
    
                initTimestampMs = System.currentTimeMillis();
                initRegistrySize = this.getApplications().size();
                registrySize = initRegistrySize;
                logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}",
                        initTimestampMs, initRegistrySize);
                //直接返回
                return; 
            }
    
            try {
                // 初始化定时任务调度器
                scheduler = Executors.newScheduledThreadPool(2,
                        new ThreadFactoryBuilder()
                                .setNameFormat("DiscoveryClient-%d")
                                .setDaemon(true)
                                .build());
                //初始化心跳的任务线程池执行器
                heartbeatExecutor = new ThreadPoolExecutor(
                        1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
                        new SynchronousQueue<Runnable>(),
                        new ThreadFactoryBuilder()
                                .setNameFormat("DiscoveryClient-HeartbeatExecutor-%d")
                                .setDaemon(true)
                                .build()
                );  // use direct handoff
                //初始化配置更新任务线程池执行器
                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();
                scheduleServerEndpointTask(eurekaTransport, args);
    
                AzToRegionMapper azToRegionMapper;
                if (clientConfig.shouldUseDnsForFetchingServiceUrls()) {
                    azToRegionMapper = new DNSBasedAzToRegionMapper(clientConfig);
                } else {
                    azToRegionMapper = new PropertyBasedAzToRegionMapper(clientConfig);
                }
                if (null != remoteRegionsToFetch.get()) {
                    azToRegionMapper.setRegionsToFetch(remoteRegionsToFetch.get().split(","));
                }
                instanceRegionChecker = new InstanceRegionChecker(azToRegionMapper, clientConfig.getRegion());
            } catch (Throwable e) {
                throw new RuntimeException("Failed to initialize DiscoveryClient!", e);
            }
            
            //是否做服务发现(从服务端拉取其他微服务信息)
            if (clientConfig.shouldFetchRegistry()) {
                try {
              //服务发现
    boolean primaryFetchRegistryResult = fetchRegistry(false); if (!primaryFetchRegistryResult) { logger.info("Initial registry fetch from primary servers failed"); } boolean backupFetchRegistryResult = true; //fetchRegistryFromBackup备用服务器 if (!primaryFetchRegistryResult && !fetchRegistryFromBackup()) { backupFetchRegistryResult = false; 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); } } // if (this.preRegistrationHandler != null) { this.preRegistrationHandler.beforeRegistration(); } if (clientConfig.shouldRegisterWithEureka() && clientConfig.shouldEnforceRegistrationAtInit()) { try { //开始注册 if (!register() ) { throw new IllegalStateException("Registration error at startup. Invalid server response."); } } catch (Throwable th) { logger.error("Registration error at startup: {}", th.getMessage()); throw new IllegalStateException(th); } } // 执行定时调度任务 initScheduledTasks(); try { Monitors.registerObject(this); } catch (Throwable e) { logger.warn("Cannot register timers", e); } // DiscoveryManager.getInstance().setDiscoveryClient(this); DiscoveryManager.getInstance().setEurekaClientConfig(config); initTimestampMs = System.currentTimeMillis(); initRegistrySize = this.getApplications().size(); registrySize = initRegistrySize; logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}", initTimestampMs, initRegistrySize); }

    执行定时调度任务

    private void initScheduledTasks() {
            if (clientConfig.shouldFetchRegistry()) {
                // 
                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()) {
                int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
                int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
                logger.info("Starting heartbeat executor: " + "renew interval is: {}", renewalIntervalInSecs);
    
                // 心跳定时任务
                heartbeatTask = new TimedSupervisorTask(
                        "heartbeat",
                        scheduler,
                        heartbeatExecutor,
                        renewalIntervalInSecs,
                        TimeUnit.SECONDS,
                        expBackOffBound,
                        new HeartbeatThread()
                );
                //添加到定时调度执行器中,定时执行
                scheduler.schedule(
                        heartbeatTask,
                        renewalIntervalInSecs, TimeUnit.SECONDS);
    
                // InstanceInfo replicator
                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()) {
                            // log at warn level if DOWN was involved
                            logger.warn("Saw local status change event {}", statusChangeEvent);
                        } else {
                            logger.info("Saw local status change event {}", statusChangeEvent);
                        }
                        instanceInfoReplicator.onDemandUpdate();
                    }
                };
    
                if (clientConfig.shouldOnDemandUpdateStatusChange()) {
                    applicationInfoManager.registerStatusChangeListener(statusChangeListener);
                }
    
                instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
            } else {
                logger.info("Not registering with Eureka server per configuration");
            }
        }

    心跳任务

        private class HeartbeatThread implements Runnable {
    
            public void run() {
                if (renew()) {
                    lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
                }
            }
        }
        boolean renew() {
            EurekaHttpResponse<InstanceInfo> httpResponse;
            try {
                //发送一次http请求
                httpResponse = eurekaTransport.registrationClient.sendHeartBeat(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);
                logger.debug(PREFIX + "{} - Heartbeat status: {}", appPathIdentifier, httpResponse.getStatusCode());
                //返回404
                if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) {
                    REREGISTER_COUNTER.increment();
                    logger.info(PREFIX + "{} - Re-registering apps/{}", appPathIdentifier, instanceInfo.getAppName());
                    long timestamp = instanceInfo.setIsDirtyWithTime();
                    //重新发起一次注册请求
                    boolean success = register();
                    if (success) {
                        instanceInfo.unsetIsDirty(timestamp);
                    }
                    return success;
                }
                return httpResponse.getStatusCode() == Status.OK.getStatusCode();
            } catch (Throwable e) {
                logger.error(PREFIX + "{} - was unable to send heartbeat!", appPathIdentifier, e);
                return false;
            }
        }

    配置刷新任务

    class CacheRefreshThread implements Runnable {
            public void run() {
                refreshRegistry();
            }
        }
        void refreshRegistry() {
            try {
                boolean isFetchingRemoteRegionRegistries = isFetchingRemoteRegionRegistries();
    
                boolean remoteRegionsModified = false;
                // This makes sure that a dynamic change to remote regions to fetch is honored.
                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
                        synchronized (instanceRegionChecker.getAzToRegionMapper()) {
                            if (remoteRegionsToFetch.compareAndSet(currentRemoteRegions, latestRemoteRegions)) {
                                String[] remoteRegions = latestRemoteRegions.split(",");
                                remoteRegionsRef.set(remoteRegions);
                                instanceRegionChecker.getAzToRegionMapper().setRegionsToFetch(remoteRegions);
                                remoteRegionsModified = true;
                            } else {
                                logger.info("Remote regions to fetch modified concurrently," +
                                        " ignoring change from {} to {}", currentRemoteRegions, latestRemoteRegions);
                            }
                        }
                    } else {
                        // Just refresh mapping to reflect any DNS/Property change
                        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);
            }
        }

    服务发现

    //forceFullRegistryFetch true:全量拉取,fasle:增量拉取
        private boolean fetchRegistry(boolean forceFullRegistryFetch) {
            Stopwatch tracer = FETCH_REGISTRY_TIMER.start();
    
            try {
                // 获取本地的缓存数据
                Applications applications = getApplications();
                
                //是否配置只获取全量
                if (clientConfig.shouldDisableDelta()
                        //是否配置vip地址(当前客户端是否对单一的注册地址感兴趣)
                        || (!Strings.isNullOrEmpty(clientConfig.getRegistryRefreshSingleVipAddress()))
                        //参数传值
                        || forceFullRegistryFetch
                        //缓存对象是null
                        || (applications == null)
                        //已注册的应用为null
                        || (applications.getRegisteredApplications().size() == 0)
                        // 版本号 -1
                        || (applications.getVersion() == -1))
                {
                    logger.info("Disable delta property : {}", clientConfig.shouldDisableDelta());
                    logger.info("Single vip registry refresh property : {}", clientConfig.getRegistryRefreshSingleVipAddress());
                    logger.info("Force full registry fetch : {}", forceFullRegistryFetch);
                    logger.info("Application is null : {}", (applications == null));
                    logger.info("Registered Applications size is zero : {}",
                            (applications.getRegisteredApplications().size() == 0));
                    logger.info("Application version is -1: {}", (applications.getVersion() == -1));
                    //全量拉取  直接发送http请求 getContainers
                    getAndStoreFullRegistry();
                } else {
                    //增量拉取
                    getAndUpdateDelta(applications);
                }
                applications.setAppsHashCode(applications.getReconcileHashCode());
                logTotalInstances();
            } catch (Throwable e) {
                logger.error(PREFIX + "{} - was unable to refresh its cache! status = {}", appPathIdentifier, e.getMessage(), e);
                return false;
            } finally {
                if (tracer != null) {
                    tracer.stop();
                }
            }
    
            // 刷新缓存
            onCacheRefreshed();
    
            // 更新实例状态
            updateInstanceRemoteStatus();
    
            return true;
        }

    全量拉取比较简单,直接发送http请求,获取到全量数据即可,重点来看一下增量拉取

    private void getAndUpdateDelta(Applications applications) throws Throwable {
            //并发原子类
            long currentUpdateGeneration = fetchRegistryGeneration.get();
    
            Applications delta = null;
            //通过http请求,获取增量信息
            EurekaHttpResponse<Applications> httpResponse = eurekaTransport.queryClient.getDelta(remoteRegionsRef.get());
            if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
                delta = httpResponse.getEntity();
            }
    
            if (delta == null) {
                logger.warn("The server does not allow the delta revision to be applied because it is not safe. "
                        + "Hence got the full registry.");
                //增量获取为null 再次请求全量信息
                getAndStoreFullRegistry();
            } else if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)) {
                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
                if (!reconcileHashCode.equals(delta.getAppsHashCode()) || clientConfig.shouldLogDeltaDiff()) {
                    reconcileAndLogDifference(delta, reconcileHashCode);  // this makes a remoteCall
                }
            } 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());
            }
        }

    增量获取的服务端源码,可到之前的文章查看,更新增量信息源码也比较简单,根据服务端返回的新增,不同的操作类型,对应不同修改逻辑,这里不再贴出了。

    服务下线

    服务下线有两种:主动下线(优雅下线),被动下线(服务宕机等情况)

    实例化EurekaClient的方法上有一个注解,@Bean(destroyMethod = "shutdown"),这个注解的意思就是当EurekaClient类型的bean被注销时,会调用shutdown方法,这种方式适用于被动下线。

    我们还可以手动调用EurekaClient的shutdown方法,例如

        @Autowired
        private EurekaClient eurekaClient;
        
        public void shutdown(){
            eurekaClient.shutdown();
        }

    就会调用到DiscoveryClient的shutdown方法

        public synchronized void shutdown() {
            if (isShutdown.compareAndSet(false, true)) {
                logger.info("Shutting down DiscoveryClient ...");
    
                if (statusChangeListener != null && applicationInfoManager != null) {
                    applicationInfoManager.unregisterStatusChangeListener(statusChangeListener.getId());
                }
                //取消定时任务
                cancelScheduledTasks();
    
                // If APPINFO was registered
                if (applicationInfoManager != null
                        && clientConfig.shouldRegisterWithEureka()
                        && clientConfig.shouldUnregisterOnShutdown()) {
                    applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN);
                    //发送http请求下线服务
                    unregister();
                }
    
                if (eurekaTransport != null) {
                    eurekaTransport.shutdown();
                }
    
                heartbeatStalenessMonitor.shutdown();
                registryStalenessMonitor.shutdown();
    
                Monitors.unregisterObject(this);
    
                logger.info("Completed shut down of DiscoveryClient");
            }
        }
  • 相关阅读:
    文本框输入内容提示消失的两种实现
    改变选择网页文字背景色
    软件增加一键处理功能
    全自动相机标定软件
    近景/低空摄影测量系统DPMatrix增加新功能
    DPMatrix软件新增了DEM/DOM制作模块,功能基本齐整!
    DPMatrix软件新增了图像匀光和色彩匹配批处理功能
    基于GPU/CUDA的全景图拼接
    基于GPU\CUDA并行处理技术的摄影测量
    软件与PATB平差数据交换
  • 原文地址:https://www.cnblogs.com/sglx/p/15735342.html
Copyright © 2011-2022 走看看