zoukankan      html  css  js  c++  java
  • EurekaClient源码分析

    EurekaClient.class

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package com.netflix.discovery;
    
    import com.google.inject.ImplementedBy;
    import com.netflix.appinfo.ApplicationInfoManager;
    import com.netflix.appinfo.HealthCheckCallback;
    import com.netflix.appinfo.HealthCheckHandler;
    import com.netflix.appinfo.InstanceInfo;
    import com.netflix.appinfo.InstanceInfo.InstanceStatus;
    import com.netflix.discovery.shared.Applications;
    import com.netflix.discovery.shared.LookupService;
    import java.util.List;
    import java.util.Set;
    import javax.annotation.Nullable;
    
    @ImplementedBy(DiscoveryClient.class)
    public interface EurekaClient extends LookupService {
        Applications getApplicationsForARegion(@Nullable String var1);
    
        Applications getApplications(String var1);
    
        List<InstanceInfo> getInstancesByVipAddress(String var1, boolean var2);
    
        List<InstanceInfo> getInstancesByVipAddress(String var1, boolean var2, @Nullable String var3);
    
        List<InstanceInfo> getInstancesByVipAddressAndAppName(String var1, String var2, boolean var3);
    
        Set<String> getAllKnownRegions();
    
        InstanceStatus getInstanceRemoteStatus();
    
        /** @deprecated */
        @Deprecated
        List<String> getDiscoveryServiceUrls(String var1);
    
        /** @deprecated */
        @Deprecated
        List<String> getServiceUrlsFromConfig(String var1, boolean var2);
    
        /** @deprecated */
        @Deprecated
        List<String> getServiceUrlsFromDNS(String var1, boolean var2);
    
        /** @deprecated */
        @Deprecated
        void registerHealthCheckCallback(HealthCheckCallback var1);
    
        void registerHealthCheck(HealthCheckHandler var1);
    
        void registerEventListener(EurekaEventListener var1);
    
        boolean unregisterEventListener(EurekaEventListener var1);
    
        HealthCheckHandler getHealthCheckHandler();
    
        void shutdown();
    
        EurekaClientConfig getEurekaClientConfig();
    
        ApplicationInfoManager getApplicationInfoManager();
    }

    健康检测器和事件监听器

    EurekaClient在LookupService上做了扩充

    提供了更丰富的获取服务实例的方法我们看一下另外两个方法

    public void registerHealthCheck(HealthCheckHandler healthCheckHandler)

    向client注册健康检查处理器,client存在一个定时任务通过HealthCheckHandler检查当前client状态

    当client状态发生变化时,将会触发新的注册事件,去更新eureka server的注册表中的服务实例信息

    通过HealthCheckHandler 实现应用状态检测

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package com.netflix.appinfo;
    
    import com.netflix.appinfo.InstanceInfo.InstanceStatus;
    
    public interface HealthCheckHandler {
        InstanceStatus getStatus(InstanceStatus var1);
    }

    HealthCheckHandler的实现类org.springframework.cloud.netflix.eureka.EurekaHealthCheckHandler

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package org.springframework.cloud.netflix.eureka;
    
    import com.netflix.appinfo.HealthCheckHandler;
    import com.netflix.appinfo.InstanceInfo.InstanceStatus;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    import java.util.Map.Entry;
    import java.util.stream.Collectors;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.boot.actuate.health.CompositeHealthIndicator;
    import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry;
    import org.springframework.boot.actuate.health.Health;
    import org.springframework.boot.actuate.health.HealthAggregator;
    import org.springframework.boot.actuate.health.HealthIndicator;
    import org.springframework.boot.actuate.health.HealthIndicatorRegistryFactory;
    import org.springframework.boot.actuate.health.Status;
    import org.springframework.boot.actuate.health.StatusAggregator;
    import org.springframework.cloud.client.discovery.health.DiscoveryCompositeHealthContributor;
    import org.springframework.cloud.client.discovery.health.DiscoveryCompositeHealthIndicator;
    import org.springframework.cloud.client.discovery.health.DiscoveryCompositeHealthIndicator.Holder;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.util.Assert;
    
    public class EurekaHealthCheckHandler implements HealthCheckHandler, ApplicationContextAware, InitializingBean {
        private static final Map<Status, InstanceStatus> STATUS_MAPPING = new HashMap<Status, InstanceStatus>() {
            {
                this.put(Status.UNKNOWN, InstanceStatus.UNKNOWN);
                this.put(Status.OUT_OF_SERVICE, InstanceStatus.OUT_OF_SERVICE);
                this.put(Status.DOWN, InstanceStatus.DOWN);
                this.put(Status.UP, InstanceStatus.UP);
            }
        };
        private StatusAggregator statusAggregator;
        private ApplicationContext applicationContext;
        private Map<String, HealthIndicator> healthIndicators;
        /** @deprecated */
        @Deprecated
        private CompositeHealthIndicator healthIndicator;
        /** @deprecated */
        @Deprecated
        private HealthIndicatorRegistryFactory healthIndicatorRegistryFactory;
        /** @deprecated */
        @Deprecated
        private HealthAggregator healthAggregator;
    
        /** @deprecated */
        @Deprecated
        public EurekaHealthCheckHandler(HealthAggregator healthAggregator) {
            Assert.notNull(healthAggregator, "HealthAggregator must not be null");
            this.healthAggregator = healthAggregator;
            this.healthIndicatorRegistryFactory = new HealthIndicatorRegistryFactory();
            this.healthIndicator = new CompositeHealthIndicator(this.healthAggregator, new DefaultHealthIndicatorRegistry());
        }
    
        public EurekaHealthCheckHandler(StatusAggregator statusAggregator) {
            this.statusAggregator = statusAggregator;
            Assert.notNull(statusAggregator, "StatusAggregator must not be null");
        }
    
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    
        public void afterPropertiesSet() throws Exception {
            Map<String, HealthIndicator> healthIndicators = this.applicationContext.getBeansOfType(HealthIndicator.class);
            this.healthIndicators = new HashMap();
            if (this.statusAggregator != null) {
                this.populateHealthIndicators(healthIndicators);
            } else {
                this.createHealthIndicator(healthIndicators);
            }
    
        }
    
        /** @deprecated */
        @Deprecated
        void createHealthIndicator(Map<String, HealthIndicator> healthIndicators) {
            Iterator var2 = healthIndicators.entrySet().iterator();
    
            while(true) {
                while(var2.hasNext()) {
                    Entry<String, HealthIndicator> entry = (Entry)var2.next();
                    if (entry.getValue() instanceof DiscoveryCompositeHealthIndicator) {
                        DiscoveryCompositeHealthIndicator indicator = (DiscoveryCompositeHealthIndicator)entry.getValue();
                        Iterator var5 = indicator.getHealthIndicators().iterator();
    
                        while(var5.hasNext()) {
                            Holder holder = (Holder)var5.next();
                            if (!(holder.getDelegate() instanceof EurekaHealthIndicator)) {
                                this.healthIndicators.put(holder.getDelegate().getName(), holder);
                            }
                        }
                    } else {
                        this.healthIndicators.put(entry.getKey(), entry.getValue());
                    }
                }
    
                this.healthIndicator = new CompositeHealthIndicator(this.healthAggregator, this.healthIndicatorRegistryFactory.createHealthIndicatorRegistry(this.healthIndicators));
                return;
            }
        }
    
        void populateHealthIndicators(Map<String, HealthIndicator> healthIndicators) {
            Iterator var2 = healthIndicators.entrySet().iterator();
    
            while(var2.hasNext()) {
                Entry<String, HealthIndicator> entry = (Entry)var2.next();
                if (entry.getValue() instanceof DiscoveryCompositeHealthContributor) {
                    DiscoveryCompositeHealthContributor indicator = (DiscoveryCompositeHealthContributor)entry.getValue();
                    indicator.forEach((contributor) -> {
                        if (!(contributor.getContributor() instanceof EurekaHealthIndicator)) {
                            this.healthIndicators.put(contributor.getName(), (HealthIndicator)contributor.getContributor());
                        }
    
                    });
                } else {
                    this.healthIndicators.put(entry.getKey(), entry.getValue());
                }
            }
    
        }
    
        public InstanceStatus getStatus(InstanceStatus instanceStatus) {
            return this.getHealthStatus();
        }
    
        protected InstanceStatus getHealthStatus() {
            Status status;
            if (this.statusAggregator != null) {
                status = this.getStatus(this.statusAggregator);
            } else {
                status = this.getStatus(this.getHealthIndicator());
            }
    
            return this.mapToInstanceStatus(status);
        }
    
        /** @deprecated */
        @Deprecated
        private Status getStatus(CompositeHealthIndicator healthIndicator) {
            Status status = healthIndicator.health().getStatus();
            return status;
        }
    
        protected Status getStatus(StatusAggregator statusAggregator) {
            Set<Status> statusSet = (Set)this.healthIndicators.values().stream().map(HealthIndicator::health).map(Health::getStatus).collect(Collectors.toSet());
            Status status = statusAggregator.getAggregateStatus(statusSet);
            return status;
        }
    
        protected InstanceStatus mapToInstanceStatus(Status status) {
            return !STATUS_MAPPING.containsKey(status) ? InstanceStatus.UNKNOWN : (InstanceStatus)STATUS_MAPPING.get(status);
        }
    
        /** @deprecated */
        @Deprecated
        protected CompositeHealthIndicator getHealthIndicator() {
            return this.healthIndicator;
        }
    }

    看其构造函数

      public EurekaHealthCheckHandler(HealthAggregator healthAggregator) {
        Assert.notNull(healthAggregator, "HealthAggregator must not be null");
        this.healthAggregator = healthAggregator;
        this.healthIndicatorRegistryFactory = new HealthIndicatorRegistryFactory();
        this.healthIndicator = new CompositeHealthIndicator(this.healthAggregator, new DefaultHealthIndicatorRegistry());
    }
    import org.springframework.boot.actuate.health.CompositeHealthIndicator;
    private final CompositeHealthIndicator healthIndicator

    此类事属于org.springframework.boot.actuate.health包下,可以得出,是通过actuator来实现对应用的检测的

    注册事件监听器,当实例信息有变时,触发对应的处理事件

    找到com.netflix.discovery.DiscoveryClient

    源码位置:https://www.cnblogs.com/YC-L/p/14474683.html#155152858

    注册函数

    public void registerEventListener(EurekaEventListener eventListener) {
        this.eventListeners.add(eventListener);
    }
    
    public boolean unregisterEventListener(EurekaEventListener eventListener) {
        return this.eventListeners.remove(eventListener);
    }

    找到EurekaDiscoveryClientConfigServiceBootstrapConfiguration.class

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package org.springframework.cloud.netflix.eureka.config;
    
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    import org.springframework.cloud.client.ReactiveCommonsClientAutoConfiguration;
    import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator;
    import org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration;
    import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration;
    import org.springframework.cloud.netflix.eureka.reactive.EurekaReactiveDiscoveryClientConfiguration;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    
    @ConditionalOnClass({ConfigServicePropertySourceLocator.class})
    @ConditionalOnProperty(
        value = {"spring.cloud.config.discovery.enabled"},
        matchIfMissing = false
    )
    @Configuration(
        proxyBeanMethods = false
    )
    @Import({EurekaDiscoveryClientConfiguration.class, EurekaClientAutoConfiguration.class, EurekaReactiveDiscoveryClientConfiguration.class, ReactiveCommonsClientAutoConfiguration.class})
    public class EurekaDiscoveryClientConfigServiceBootstrapConfiguration {
        public EurekaDiscoveryClientConfigServiceBootstrapConfiguration() {
        }
    }
    @Import({EurekaDiscoveryClientConfiguration.class, EurekaClientAutoConfiguration.class, EurekaReactiveDiscoveryClientConfiguration.class, ReactiveCommonsClientAutoConfiguration.class})

    注解中有个类: EurekaClientAutoConfiguration

     public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config, EurekaInstanceConfig instance, @Autowired(required = false) HealthCheckHandler healthCheckHandler) {
                ApplicationInfoManager appManager;
                if (AopUtils.isAopProxy(manager)) {
                    appManager = (ApplicationInfoManager)ProxyUtils.getTargetObject(manager);
                } else {
                    appManager = manager;
                }
    
                CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager, config, this.optionalArgs, this.context);
                cloudEurekaClient.registerHealthCheck(healthCheckHandler);
                return cloudEurekaClient;
            }

    CloudEurekaClient.class

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package org.springframework.cloud.netflix.eureka;
    
    import com.netflix.appinfo.ApplicationInfoManager;
    import com.netflix.appinfo.InstanceInfo;
    import com.netflix.appinfo.InstanceInfo.InstanceStatus;
    import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs;
    import com.netflix.discovery.DiscoveryClient;
    import com.netflix.discovery.EurekaClientConfig;
    import com.netflix.discovery.shared.transport.EurekaHttpClient;
    import com.netflix.discovery.shared.transport.EurekaHttpResponse;
    import java.lang.reflect.Field;
    import java.util.concurrent.atomic.AtomicLong;
    import java.util.concurrent.atomic.AtomicReference;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.http.HttpStatus;
    import org.springframework.util.ReflectionUtils;
    
    public class CloudEurekaClient extends DiscoveryClient {
        private static final Log log = LogFactory.getLog(CloudEurekaClient.class);
        private final AtomicLong cacheRefreshedCount;
        private ApplicationEventPublisher publisher;
        private Field eurekaTransportField;
        private ApplicationInfoManager applicationInfoManager;
        private AtomicReference<EurekaHttpClient> eurekaHttpClient;
    
        public CloudEurekaClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, ApplicationEventPublisher publisher) {
            this(applicationInfoManager, config, (AbstractDiscoveryClientOptionalArgs)null, publisher);
        }
    
        public CloudEurekaClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs<?> args, ApplicationEventPublisher publisher) {
            super(applicationInfoManager, config, args);
            this.cacheRefreshedCount = new AtomicLong(0L);
            this.eurekaHttpClient = new AtomicReference();
            this.applicationInfoManager = applicationInfoManager;
            this.publisher = publisher;
            this.eurekaTransportField = ReflectionUtils.findField(DiscoveryClient.class, "eurekaTransport");
            ReflectionUtils.makeAccessible(this.eurekaTransportField);
        }
    
        public ApplicationInfoManager getApplicationInfoManager() {
            return this.applicationInfoManager;
        }
    
        public void cancelOverrideStatus(InstanceInfo info) {
            this.getEurekaHttpClient().deleteStatusOverride(info.getAppName(), info.getId(), info);
        }
    
        public InstanceInfo getInstanceInfo(String appname, String instanceId) {
            EurekaHttpResponse<InstanceInfo> response = this.getEurekaHttpClient().getInstance(appname, instanceId);
            HttpStatus httpStatus = HttpStatus.valueOf(response.getStatusCode());
            return httpStatus.is2xxSuccessful() && response.getEntity() != null ? (InstanceInfo)response.getEntity() : null;
        }
    
        EurekaHttpClient getEurekaHttpClient() {
            if (this.eurekaHttpClient.get() == null) {
                try {
                    Object eurekaTransport = this.eurekaTransportField.get(this);
                    Field registrationClientField = ReflectionUtils.findField(eurekaTransport.getClass(), "registrationClient");
                    ReflectionUtils.makeAccessible(registrationClientField);
                    this.eurekaHttpClient.compareAndSet((Object)null, (EurekaHttpClient)registrationClientField.get(eurekaTransport));
                } catch (IllegalAccessException var3) {
                    log.error("error getting EurekaHttpClient", var3);
                }
            }
    
            return (EurekaHttpClient)this.eurekaHttpClient.get();
        }
    
        public void setStatus(InstanceStatus newStatus, InstanceInfo info) {
            this.getEurekaHttpClient().statusUpdate(info.getAppName(), info.getId(), newStatus, info);
        }
    
        protected void onCacheRefreshed() {
            super.onCacheRefreshed();
            if (this.cacheRefreshedCount != null) {
                long newCount = this.cacheRefreshedCount.incrementAndGet();
                log.trace("onCacheRefreshed called with count: " + newCount);
                this.publisher.publishEvent(new HeartbeatEvent(this, newCount));
            }
    
        }
    }

    com.netflix.discovery.DiscoveryClient构造函数-不注册不拉取

    DiscoveryClient的构造函数

    public DiscoveryClient(ApplicationInfoManager applicationInfoManager, final EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, EndpointRandomizer randomizer) {}

    此方法中依次执行以下步骤,贯穿了Eureka Client启动阶段的各项工作

    • 从eureka server中拉取注册表
    • 服务注册
    • 初始化发送心跳
    • 缓存刷新(定时拉取注册表信息)
    • 按需注册定时任务等

    构造函数中查找

     if (config.shouldFetchRegistry()) {
                this.registryStalenessMonitor = new ThresholdLevelsMetric(this, "eurekaClient.registry.lastUpdateSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
            } else {
                this.registryStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
            }
    
            if (config.shouldRegisterWithEureka()) {
                this.heartbeatStalenessMonitor = new ThresholdLevelsMetric(this, "eurekaClient.registration.lastHeartbeatSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
            } else {
                this.heartbeatStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
            }

    点其实现类EurekaClientConfigBean

    shouldRegistry返回一个boolean值,fetchRegistry,默认是true,表示client从server拉取注册表信息

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package org.springframework.cloud.netflix.eureka;
    
    import com.netflix.appinfo.EurekaAccept;
    import com.netflix.discovery.EurekaClientConfig;
    import com.netflix.discovery.shared.transport.EurekaTransportConfig;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.context.properties.NestedConfigurationProperty;
    import org.springframework.core.Ordered;
    import org.springframework.core.env.PropertyResolver;
    import org.springframework.util.StringUtils;
    
    @ConfigurationProperties("eureka.client")
    public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
        public static final String PREFIX = "eureka.client";
        public static final String DEFAULT_URL = "http://localhost:8761/eureka/";
        public static final String DEFAULT_ZONE = "defaultZone";
        private static final int MINUTES = 60;
        @Autowired(
            required = false
        )
        PropertyResolver propertyResolver;
        private boolean enabled = true;
        @NestedConfigurationProperty
        private EurekaTransportConfig transport = new CloudEurekaTransportConfig();
        private int registryFetchIntervalSeconds = 30;
        private int instanceInfoReplicationIntervalSeconds = 30;
        private int initialInstanceInfoReplicationIntervalSeconds = 40;
        private int eurekaServiceUrlPollIntervalSeconds = 300;
        private String proxyPort;
        private String proxyHost;
        private String proxyUserName;
        private String proxyPassword;
        private int eurekaServerReadTimeoutSeconds = 8;
        private int eurekaServerConnectTimeoutSeconds = 5;
        private String backupRegistryImpl;
        private int eurekaServerTotalConnections = 200;
        private int eurekaServerTotalConnectionsPerHost = 50;
        private String eurekaServerURLContext;
        private String eurekaServerPort;
        private String eurekaServerDNSName;
        private String region = "us-east-1";
        private int eurekaConnectionIdleTimeoutSeconds = 30;
        private String registryRefreshSingleVipAddress;
        private int heartbeatExecutorThreadPoolSize = 2;
        private int heartbeatExecutorExponentialBackOffBound = 10;
        private int cacheRefreshExecutorThreadPoolSize = 2;
        private int cacheRefreshExecutorExponentialBackOffBound = 10;
        private Map<String, String> serviceUrl = new HashMap();
        private boolean gZipContent;
        private boolean useDnsForFetchingServiceUrls;
        private boolean registerWithEureka;
        private boolean preferSameZoneEureka;
        private boolean logDeltaDiff;
        private boolean disableDelta;
        private String fetchRemoteRegionsRegistry;
        private Map<String, String> availabilityZones;
        private boolean filterOnlyUpInstances;
        private boolean fetchRegistry;
        private String dollarReplacement;
        private String escapeCharReplacement;
        private boolean allowRedirects;
        private boolean onDemandUpdateStatusChange;
        private String encoderName;
        private String decoderName;
        private String clientDataAccept;
        private boolean shouldUnregisterOnShutdown;
        private boolean shouldEnforceRegistrationAtInit;
        private int order;
    
        public EurekaClientConfigBean() {
            this.serviceUrl.put("defaultZone", "http://localhost:8761/eureka/");
            this.gZipContent = true;
            this.useDnsForFetchingServiceUrls = false;
            this.registerWithEureka = true;
            this.preferSameZoneEureka = true;
            this.availabilityZones = new HashMap();
            this.filterOnlyUpInstances = true;
            this.fetchRegistry = true;
            this.dollarReplacement = "_-";
            this.escapeCharReplacement = "__";
            this.allowRedirects = false;
            this.onDemandUpdateStatusChange = true;
            this.clientDataAccept = EurekaAccept.full.name();
            this.shouldUnregisterOnShutdown = true;
            this.shouldEnforceRegistrationAtInit = false;
            this.order = 0;
        }
    
        public boolean shouldGZipContent() {
            return this.gZipContent;
        }
    
        public boolean shouldUseDnsForFetchingServiceUrls() {
            return this.useDnsForFetchingServiceUrls;
        }
    
        public boolean shouldRegisterWithEureka() {
            return this.registerWithEureka;
        }
    
        public boolean shouldPreferSameZoneEureka() {
            return this.preferSameZoneEureka;
        }
    
        public boolean shouldLogDeltaDiff() {
            return this.logDeltaDiff;
        }
    
        public boolean shouldDisableDelta() {
            return this.disableDelta;
        }
    
        public boolean shouldUnregisterOnShutdown() {
            return this.shouldUnregisterOnShutdown;
        }
    
        public boolean shouldEnforceRegistrationAtInit() {
            return this.shouldEnforceRegistrationAtInit;
        }
    
        public String fetchRegistryForRemoteRegions() {
            return this.fetchRemoteRegionsRegistry;
        }
    
        public String[] getAvailabilityZones(String region) {
            String value = (String)this.availabilityZones.get(region);
            if (value == null) {
                value = "defaultZone";
            }
    
            return value.split(",");
        }
    
        public List<String> getEurekaServerServiceUrls(String myZone) {
            String serviceUrls = (String)this.serviceUrl.get(myZone);
            if (serviceUrls == null || serviceUrls.isEmpty()) {
                serviceUrls = (String)this.serviceUrl.get("defaultZone");
            }
    
            if (!StringUtils.isEmpty(serviceUrls)) {
                String[] serviceUrlsSplit = StringUtils.commaDelimitedListToStringArray(serviceUrls);
                List<String> eurekaServiceUrls = new ArrayList(serviceUrlsSplit.length);
                String[] var5 = serviceUrlsSplit;
                int var6 = serviceUrlsSplit.length;
    
                for(int var7 = 0; var7 < var6; ++var7) {
                    String eurekaServiceUrl = var5[var7];
                    if (!this.endsWithSlash(eurekaServiceUrl)) {
                        eurekaServiceUrl = eurekaServiceUrl + "/";
                    }
    
                    eurekaServiceUrls.add(eurekaServiceUrl.trim());
                }
    
                return eurekaServiceUrls;
            } else {
                return new ArrayList();
            }
        }
    
        private boolean endsWithSlash(String url) {
            return url.endsWith("/");
        }
    
        public boolean shouldFilterOnlyUpInstances() {
            return this.filterOnlyUpInstances;
        }
    
        public boolean shouldFetchRegistry() {
            return this.fetchRegistry;
        }
    
        public boolean allowRedirects() {
            return this.allowRedirects;
        }
    
        public boolean shouldOnDemandUpdateStatusChange() {
            return this.onDemandUpdateStatusChange;
        }
    
        public String getExperimental(String name) {
            return this.propertyResolver != null ? (String)this.propertyResolver.getProperty("eureka.client.experimental." + name, String.class, (Object)null) : null;
        }
    
        public EurekaTransportConfig getTransportConfig() {
            return this.getTransport();
        }
    
        public PropertyResolver getPropertyResolver() {
            return this.propertyResolver;
        }
    
        public void setPropertyResolver(PropertyResolver propertyResolver) {
            this.propertyResolver = propertyResolver;
        }
    
        public boolean isEnabled() {
            return this.enabled;
        }
    
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
        }
    
        public EurekaTransportConfig getTransport() {
            return this.transport;
        }
    
        public void setTransport(EurekaTransportConfig transport) {
            this.transport = transport;
        }
    
        public int getRegistryFetchIntervalSeconds() {
            return this.registryFetchIntervalSeconds;
        }
    
        public void setRegistryFetchIntervalSeconds(int registryFetchIntervalSeconds) {
            this.registryFetchIntervalSeconds = registryFetchIntervalSeconds;
        }
    
        public int getInstanceInfoReplicationIntervalSeconds() {
            return this.instanceInfoReplicationIntervalSeconds;
        }
    
        public void setInstanceInfoReplicationIntervalSeconds(int instanceInfoReplicationIntervalSeconds) {
            this.instanceInfoReplicationIntervalSeconds = instanceInfoReplicationIntervalSeconds;
        }
    
        public int getInitialInstanceInfoReplicationIntervalSeconds() {
            return this.initialInstanceInfoReplicationIntervalSeconds;
        }
    
        public void setInitialInstanceInfoReplicationIntervalSeconds(int initialInstanceInfoReplicationIntervalSeconds) {
            this.initialInstanceInfoReplicationIntervalSeconds = initialInstanceInfoReplicationIntervalSeconds;
        }
    
        public int getEurekaServiceUrlPollIntervalSeconds() {
            return this.eurekaServiceUrlPollIntervalSeconds;
        }
    
        public void setEurekaServiceUrlPollIntervalSeconds(int eurekaServiceUrlPollIntervalSeconds) {
            this.eurekaServiceUrlPollIntervalSeconds = eurekaServiceUrlPollIntervalSeconds;
        }
    
        public String getProxyPort() {
            return this.proxyPort;
        }
    
        public void setProxyPort(String proxyPort) {
            this.proxyPort = proxyPort;
        }
    
        public String getProxyHost() {
            return this.proxyHost;
        }
    
        public void setProxyHost(String proxyHost) {
            this.proxyHost = proxyHost;
        }
    
        public String getProxyUserName() {
            return this.proxyUserName;
        }
    
        public void setProxyUserName(String proxyUserName) {
            this.proxyUserName = proxyUserName;
        }
    
        public String getProxyPassword() {
            return this.proxyPassword;
        }
    
        public void setProxyPassword(String proxyPassword) {
            this.proxyPassword = proxyPassword;
        }
    
        public int getEurekaServerReadTimeoutSeconds() {
            return this.eurekaServerReadTimeoutSeconds;
        }
    
        public void setEurekaServerReadTimeoutSeconds(int eurekaServerReadTimeoutSeconds) {
            this.eurekaServerReadTimeoutSeconds = eurekaServerReadTimeoutSeconds;
        }
    
        public int getEurekaServerConnectTimeoutSeconds() {
            return this.eurekaServerConnectTimeoutSeconds;
        }
    
        public void setEurekaServerConnectTimeoutSeconds(int eurekaServerConnectTimeoutSeconds) {
            this.eurekaServerConnectTimeoutSeconds = eurekaServerConnectTimeoutSeconds;
        }
    
        public String getBackupRegistryImpl() {
            return this.backupRegistryImpl;
        }
    
        public void setBackupRegistryImpl(String backupRegistryImpl) {
            this.backupRegistryImpl = backupRegistryImpl;
        }
    
        public int getEurekaServerTotalConnections() {
            return this.eurekaServerTotalConnections;
        }
    
        public void setEurekaServerTotalConnections(int eurekaServerTotalConnections) {
            this.eurekaServerTotalConnections = eurekaServerTotalConnections;
        }
    
        public int getEurekaServerTotalConnectionsPerHost() {
            return this.eurekaServerTotalConnectionsPerHost;
        }
    
        public void setEurekaServerTotalConnectionsPerHost(int eurekaServerTotalConnectionsPerHost) {
            this.eurekaServerTotalConnectionsPerHost = eurekaServerTotalConnectionsPerHost;
        }
    
        public String getEurekaServerURLContext() {
            return this.eurekaServerURLContext;
        }
    
        public void setEurekaServerURLContext(String eurekaServerURLContext) {
            this.eurekaServerURLContext = eurekaServerURLContext;
        }
    
        public String getEurekaServerPort() {
            return this.eurekaServerPort;
        }
    
        public void setEurekaServerPort(String eurekaServerPort) {
            this.eurekaServerPort = eurekaServerPort;
        }
    
        public String getEurekaServerDNSName() {
            return this.eurekaServerDNSName;
        }
    
        public void setEurekaServerDNSName(String eurekaServerDNSName) {
            this.eurekaServerDNSName = eurekaServerDNSName;
        }
    
        public String getRegion() {
            return this.region;
        }
    
        public void setRegion(String region) {
            this.region = region;
        }
    
        public int getEurekaConnectionIdleTimeoutSeconds() {
            return this.eurekaConnectionIdleTimeoutSeconds;
        }
    
        public void setEurekaConnectionIdleTimeoutSeconds(int eurekaConnectionIdleTimeoutSeconds) {
            this.eurekaConnectionIdleTimeoutSeconds = eurekaConnectionIdleTimeoutSeconds;
        }
    
        public String getRegistryRefreshSingleVipAddress() {
            return this.registryRefreshSingleVipAddress;
        }
    
        public void setRegistryRefreshSingleVipAddress(String registryRefreshSingleVipAddress) {
            this.registryRefreshSingleVipAddress = registryRefreshSingleVipAddress;
        }
    
        public int getHeartbeatExecutorThreadPoolSize() {
            return this.heartbeatExecutorThreadPoolSize;
        }
    
        public void setHeartbeatExecutorThreadPoolSize(int heartbeatExecutorThreadPoolSize) {
            this.heartbeatExecutorThreadPoolSize = heartbeatExecutorThreadPoolSize;
        }
    
        public int getHeartbeatExecutorExponentialBackOffBound() {
            return this.heartbeatExecutorExponentialBackOffBound;
        }
    
        public void setHeartbeatExecutorExponentialBackOffBound(int heartbeatExecutorExponentialBackOffBound) {
            this.heartbeatExecutorExponentialBackOffBound = heartbeatExecutorExponentialBackOffBound;
        }
    
        public int getCacheRefreshExecutorThreadPoolSize() {
            return this.cacheRefreshExecutorThreadPoolSize;
        }
    
        public void setCacheRefreshExecutorThreadPoolSize(int cacheRefreshExecutorThreadPoolSize) {
            this.cacheRefreshExecutorThreadPoolSize = cacheRefreshExecutorThreadPoolSize;
        }
    
        public int getCacheRefreshExecutorExponentialBackOffBound() {
            return this.cacheRefreshExecutorExponentialBackOffBound;
        }
    
        public void setCacheRefreshExecutorExponentialBackOffBound(int cacheRefreshExecutorExponentialBackOffBound) {
            this.cacheRefreshExecutorExponentialBackOffBound = cacheRefreshExecutorExponentialBackOffBound;
        }
    
        public Map<String, String> getServiceUrl() {
            return this.serviceUrl;
        }
    
        public void setServiceUrl(Map<String, String> serviceUrl) {
            this.serviceUrl = serviceUrl;
        }
    
        public boolean isgZipContent() {
            return this.gZipContent;
        }
    
        public void setgZipContent(boolean gZipContent) {
            this.gZipContent = gZipContent;
        }
    
        public boolean isUseDnsForFetchingServiceUrls() {
            return this.useDnsForFetchingServiceUrls;
        }
    
        public void setUseDnsForFetchingServiceUrls(boolean useDnsForFetchingServiceUrls) {
            this.useDnsForFetchingServiceUrls = useDnsForFetchingServiceUrls;
        }
    
        public boolean isRegisterWithEureka() {
            return this.registerWithEureka;
        }
    
        public void setRegisterWithEureka(boolean registerWithEureka) {
            this.registerWithEureka = registerWithEureka;
        }
    
        public boolean isPreferSameZoneEureka() {
            return this.preferSameZoneEureka;
        }
    
        public void setPreferSameZoneEureka(boolean preferSameZoneEureka) {
            this.preferSameZoneEureka = preferSameZoneEureka;
        }
    
        public boolean isLogDeltaDiff() {
            return this.logDeltaDiff;
        }
    
        public void setLogDeltaDiff(boolean logDeltaDiff) {
            this.logDeltaDiff = logDeltaDiff;
        }
    
        public boolean isDisableDelta() {
            return this.disableDelta;
        }
    
        public void setDisableDelta(boolean disableDelta) {
            this.disableDelta = disableDelta;
        }
    
        public String getFetchRemoteRegionsRegistry() {
            return this.fetchRemoteRegionsRegistry;
        }
    
        public void setFetchRemoteRegionsRegistry(String fetchRemoteRegionsRegistry) {
            this.fetchRemoteRegionsRegistry = fetchRemoteRegionsRegistry;
        }
    
        public Map<String, String> getAvailabilityZones() {
            return this.availabilityZones;
        }
    
        public void setAvailabilityZones(Map<String, String> availabilityZones) {
            this.availabilityZones = availabilityZones;
        }
    
        public boolean isFilterOnlyUpInstances() {
            return this.filterOnlyUpInstances;
        }
    
        public void setFilterOnlyUpInstances(boolean filterOnlyUpInstances) {
            this.filterOnlyUpInstances = filterOnlyUpInstances;
        }
    
        public boolean isFetchRegistry() {
            return this.fetchRegistry;
        }
    
        public void setFetchRegistry(boolean fetchRegistry) {
            this.fetchRegistry = fetchRegistry;
        }
    
        public String getDollarReplacement() {
            return this.dollarReplacement;
        }
    
        public void setDollarReplacement(String dollarReplacement) {
            this.dollarReplacement = dollarReplacement;
        }
    
        public String getEscapeCharReplacement() {
            return this.escapeCharReplacement;
        }
    
        public void setEscapeCharReplacement(String escapeCharReplacement) {
            this.escapeCharReplacement = escapeCharReplacement;
        }
    
        public boolean isAllowRedirects() {
            return this.allowRedirects;
        }
    
        public void setAllowRedirects(boolean allowRedirects) {
            this.allowRedirects = allowRedirects;
        }
    
        public boolean isOnDemandUpdateStatusChange() {
            return this.onDemandUpdateStatusChange;
        }
    
        public void setOnDemandUpdateStatusChange(boolean onDemandUpdateStatusChange) {
            this.onDemandUpdateStatusChange = onDemandUpdateStatusChange;
        }
    
        public String getEncoderName() {
            return this.encoderName;
        }
    
        public void setEncoderName(String encoderName) {
            this.encoderName = encoderName;
        }
    
        public String getDecoderName() {
            return this.decoderName;
        }
    
        public void setDecoderName(String decoderName) {
            this.decoderName = decoderName;
        }
    
        public String getClientDataAccept() {
            return this.clientDataAccept;
        }
    
        public void setClientDataAccept(String clientDataAccept) {
            this.clientDataAccept = clientDataAccept;
        }
    
        public boolean isShouldUnregisterOnShutdown() {
            return this.shouldUnregisterOnShutdown;
        }
    
        public void setShouldUnregisterOnShutdown(boolean shouldUnregisterOnShutdown) {
            this.shouldUnregisterOnShutdown = shouldUnregisterOnShutdown;
        }
    
        public boolean isShouldEnforceRegistrationAtInit() {
            return this.shouldEnforceRegistrationAtInit;
        }
    
        public void setShouldEnforceRegistrationAtInit(boolean shouldEnforceRegistrationAtInit) {
            this.shouldEnforceRegistrationAtInit = shouldEnforceRegistrationAtInit;
        }
    
        public int getOrder() {
            return this.order;
        }
    
        public void setOrder(int order) {
            this.order = order;
        }
    
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            } else if (o != null && this.getClass() == o.getClass()) {
                EurekaClientConfigBean that = (EurekaClientConfigBean)o;
                return Objects.equals(this.propertyResolver, that.propertyResolver) && this.enabled == that.enabled && Objects.equals(this.transport, that.transport) && this.registryFetchIntervalSeconds == that.registryFetchIntervalSeconds && this.instanceInfoReplicationIntervalSeconds == that.instanceInfoReplicationIntervalSeconds && this.initialInstanceInfoReplicationIntervalSeconds == that.initialInstanceInfoReplicationIntervalSeconds && this.eurekaServiceUrlPollIntervalSeconds == that.eurekaServiceUrlPollIntervalSeconds && this.eurekaServerReadTimeoutSeconds == that.eurekaServerReadTimeoutSeconds && this.eurekaServerConnectTimeoutSeconds == that.eurekaServerConnectTimeoutSeconds && this.eurekaServerTotalConnections == that.eurekaServerTotalConnections && this.eurekaServerTotalConnectionsPerHost == that.eurekaServerTotalConnectionsPerHost && this.eurekaConnectionIdleTimeoutSeconds == that.eurekaConnectionIdleTimeoutSeconds && this.heartbeatExecutorThreadPoolSize == that.heartbeatExecutorThreadPoolSize && this.heartbeatExecutorExponentialBackOffBound == that.heartbeatExecutorExponentialBackOffBound && this.cacheRefreshExecutorThreadPoolSize == that.cacheRefreshExecutorThreadPoolSize && this.cacheRefreshExecutorExponentialBackOffBound == that.cacheRefreshExecutorExponentialBackOffBound && this.gZipContent == that.gZipContent && this.useDnsForFetchingServiceUrls == that.useDnsForFetchingServiceUrls && this.registerWithEureka == that.registerWithEureka && this.preferSameZoneEureka == that.preferSameZoneEureka && this.logDeltaDiff == that.logDeltaDiff && this.disableDelta == that.disableDelta && this.filterOnlyUpInstances == that.filterOnlyUpInstances && this.fetchRegistry == that.fetchRegistry && this.allowRedirects == that.allowRedirects && this.onDemandUpdateStatusChange == that.onDemandUpdateStatusChange && this.shouldUnregisterOnShutdown == that.shouldUnregisterOnShutdown && this.shouldEnforceRegistrationAtInit == that.shouldEnforceRegistrationAtInit && Objects.equals(this.proxyPort, that.proxyPort) && Objects.equals(this.proxyHost, that.proxyHost) && Objects.equals(this.proxyUserName, that.proxyUserName) && Objects.equals(this.proxyPassword, that.proxyPassword) && Objects.equals(this.backupRegistryImpl, that.backupRegistryImpl) && Objects.equals(this.eurekaServerURLContext, that.eurekaServerURLContext) && Objects.equals(this.eurekaServerPort, that.eurekaServerPort) && Objects.equals(this.eurekaServerDNSName, that.eurekaServerDNSName) && Objects.equals(this.region, that.region) && Objects.equals(this.registryRefreshSingleVipAddress, that.registryRefreshSingleVipAddress) && Objects.equals(this.serviceUrl, that.serviceUrl) && Objects.equals(this.fetchRemoteRegionsRegistry, that.fetchRemoteRegionsRegistry) && Objects.equals(this.availabilityZones, that.availabilityZones) && Objects.equals(this.dollarReplacement, that.dollarReplacement) && Objects.equals(this.escapeCharReplacement, that.escapeCharReplacement) && Objects.equals(this.encoderName, that.encoderName) && Objects.equals(this.decoderName, that.decoderName) && Objects.equals(this.clientDataAccept, that.clientDataAccept) && Objects.equals(this.order, that.order);
            } else {
                return false;
            }
        }
    
        public int hashCode() {
            return Objects.hash(new Object[]{this.propertyResolver, this.enabled, this.transport, this.registryFetchIntervalSeconds, this.instanceInfoReplicationIntervalSeconds, this.initialInstanceInfoReplicationIntervalSeconds, this.eurekaServiceUrlPollIntervalSeconds, this.proxyPort, this.proxyHost, this.proxyUserName, this.proxyPassword, this.eurekaServerReadTimeoutSeconds, this.eurekaServerConnectTimeoutSeconds, this.backupRegistryImpl, this.eurekaServerTotalConnections, this.eurekaServerTotalConnectionsPerHost, this.eurekaServerURLContext, this.eurekaServerPort, this.eurekaServerDNSName, this.region, this.eurekaConnectionIdleTimeoutSeconds, this.registryRefreshSingleVipAddress, this.heartbeatExecutorThreadPoolSize, this.heartbeatExecutorExponentialBackOffBound, this.cacheRefreshExecutorThreadPoolSize, this.cacheRefreshExecutorExponentialBackOffBound, this.serviceUrl, this.gZipContent, this.useDnsForFetchingServiceUrls, this.registerWithEureka, this.preferSameZoneEureka, this.logDeltaDiff, this.disableDelta, this.fetchRemoteRegionsRegistry, this.availabilityZones, this.filterOnlyUpInstances, this.fetchRegistry, this.dollarReplacement, this.escapeCharReplacement, this.allowRedirects, this.onDemandUpdateStatusChange, this.encoderName, this.decoderName, this.clientDataAccept, this.shouldUnregisterOnShutdown, this.shouldEnforceRegistrationAtInit, this.order});
        }
    
        public String toString() {
            return "EurekaClientConfigBean{" + "propertyResolver=" + this.propertyResolver + ", " + "enabled=" + this.enabled + ", " + "transport=" + this.transport + ", " + "registryFetchIntervalSeconds=" + this.registryFetchIntervalSeconds + ", " + "instanceInfoReplicationIntervalSeconds=" + this.instanceInfoReplicationIntervalSeconds + ", " + "initialInstanceInfoReplicationIntervalSeconds=" + this.initialInstanceInfoReplicationIntervalSeconds + ", " + "eurekaServiceUrlPollIntervalSeconds=" + this.eurekaServiceUrlPollIntervalSeconds + ", " + "proxyPort='" + this.proxyPort + "', " + "proxyHost='" + this.proxyHost + "', " + "proxyUserName='" + this.proxyUserName + "', " + "proxyPassword='" + this.proxyPassword + "', " + "eurekaServerReadTimeoutSeconds=" + this.eurekaServerReadTimeoutSeconds + ", " + "eurekaServerConnectTimeoutSeconds=" + this.eurekaServerConnectTimeoutSeconds + ", " + "backupRegistryImpl='" + this.backupRegistryImpl + "', " + "eurekaServerTotalConnections=" + this.eurekaServerTotalConnections + ", " + "eurekaServerTotalConnectionsPerHost=" + this.eurekaServerTotalConnectionsPerHost + ", " + "eurekaServerURLContext='" + this.eurekaServerURLContext + "', " + "eurekaServerPort='" + this.eurekaServerPort + "', " + "eurekaServerDNSName='" + this.eurekaServerDNSName + "', " + "region='" + this.region + "', " + "eurekaConnectionIdleTimeoutSeconds=" + this.eurekaConnectionIdleTimeoutSeconds + ", " + "registryRefreshSingleVipAddress='" + this.registryRefreshSingleVipAddress + "', " + "heartbeatExecutorThreadPoolSize=" + this.heartbeatExecutorThreadPoolSize + ", " + "heartbeatExecutorExponentialBackOffBound=" + this.heartbeatExecutorExponentialBackOffBound + ", " + "cacheRefreshExecutorThreadPoolSize=" + this.cacheRefreshExecutorThreadPoolSize + ", " + "cacheRefreshExecutorExponentialBackOffBound=" + this.cacheRefreshExecutorExponentialBackOffBound + ", " + "serviceUrl=" + this.serviceUrl + ", " + "gZipContent=" + this.gZipContent + ", " + "useDnsForFetchingServiceUrls=" + this.useDnsForFetchingServiceUrls + ", " + "registerWithEureka=" + this.registerWithEureka + ", " + "preferSameZoneEureka=" + this.preferSameZoneEureka + ", " + "logDeltaDiff=" + this.logDeltaDiff + ", " + "disableDelta=" + this.disableDelta + ", " + "fetchRemoteRegionsRegistry='" + this.fetchRemoteRegionsRegistry + "', " + "availabilityZones=" + this.availabilityZones + ", " + "filterOnlyUpInstances=" + this.filterOnlyUpInstances + ", " + "fetchRegistry=" + this.fetchRegistry + ", " + "dollarReplacement='" + this.dollarReplacement + "', " + "escapeCharReplacement='" + this.escapeCharReplacement + "', " + "allowRedirects=" + this.allowRedirects + ", " + "onDemandUpdateStatusChange=" + this.onDemandUpdateStatusChange + ", " + "encoderName='" + this.encoderName + "', " + "decoderName='" + this.decoderName + "', " + "clientDataAccept='" + this.clientDataAccept + "', " + "shouldUnregisterOnShutdown='" + this.shouldUnregisterOnShutdown + "', " + "shouldEnforceRegistrationAtInit='" + this.shouldEnforceRegistrationAtInit + "', " + "order='" + this.order + "'}";
        }
    }

    继续看DiscoveryClient中的源码

    if (config.shouldRegisterWithEureka()) {
        this.heartbeatStalenessMonitor = new ThresholdLevelsMetric(this, "eurekaClient.registration.lastHeartbeatSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
    } else {
        this.heartbeatStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
    }

    点其实现类EurekaClientConfigBean

    shouldRegisterWithEureka 返回一个boolean值 registerWithEureka,默认为true,表示client将注册到server

    继续看DiscoveryClient源码

    if (!config.shouldRegisterWithEureka() && !config.shouldFetchRegistry()) {
        logger.info("Client configured to neither register nor query for data.");
        this.scheduler = null;
        this.heartbeatExecutor = null;
        this.cacheRefreshExecutor = null;
        this.eurekaTransport = null;
        this.instanceRegionChecker = new InstanceRegionChecker(new PropertyBasedAzToRegionMapper(config), this.clientConfig.getRegion());
        DiscoveryManager.getInstance().setDiscoveryClient(this);
        DiscoveryManager.getInstance().setEurekaClientConfig(config);
        this.initTimestampMs = System.currentTimeMillis();
        logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}", this.initTimestampMs, this.getApplications().size());
    } else {}

    如果shouldRegisterWithEureka和shouldFetchRegistry两个都为false,则直接返回,构造方法执行结束,既不服务注册,也不服务发现

    com.netflix.discovery.DiscoveryClient构造函数-两个定时任务

    顺着上段代码中的else往下看

    try {
        this.scheduler = Executors.newScheduledThreadPool(2, (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-%d").setDaemon(true).build());
        this.heartbeatExecutor = new ThreadPoolExecutor(1, this.clientConfig.getHeartbeatExecutorThreadPoolSize(), 0L, TimeUnit.SECONDS, new SynchronousQueue(), (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-HeartbeatExecutor-%d").setDaemon(true).build());
        this.cacheRefreshExecutor = new ThreadPoolExecutor(1, this.clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0L, TimeUnit.SECONDS, new SynchronousQueue(), (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d").setDaemon(true).build());
        this.eurekaTransport = new DiscoveryClient.EurekaTransport();
        this.scheduleServerEndpointTask(this.eurekaTransport, args);
        Object azToRegionMapper;
        if (this.clientConfig.shouldUseDnsForFetchingServiceUrls()) {
            azToRegionMapper = new DNSBasedAzToRegionMapper(this.clientConfig);
        } else {
            azToRegionMapper = new PropertyBasedAzToRegionMapper(this.clientConfig);
        }
    
        if (null != this.remoteRegionsToFetch.get()) {
            ((AzToRegionMapper)azToRegionMapper).setRegionsToFetch(((String)this.remoteRegionsToFetch.get()).split(","));
        }
    
        this.instanceRegionChecker = new InstanceRegionChecker((AzToRegionMapper)azToRegionMapper, this.clientConfig.getRegion());
    } catch (Throwable var10) {
        throw new RuntimeException("Failed to initialize DiscoveryClient!", var10);
    }
    • scheduler定义了一个基于线程池的定时器线程池,大小为2
    • heartbeatExecutor:用于发送心跳
    • cacheRefreshExecutor:用于刷新缓存
    • eurekaTransport,它是eureka Client和eureka server进行http交互jersey客户端

    com.netflix.discovery.DiscoveryClient构造函数-client和server交互的Jersey客户端

    com.netflix.discovery.DiscoveryClient构造函数-拉取注册信息

    if (this.clientConfig.shouldFetchRegistry() && !this.fetchRegistry(false)) {
        this.fetchRegistryFromBackup();
    }

    符合上面这个条件,执行fetchRegistry,从eureka server拉取注册表信息,缓存到本地,减少server交互

    com.netflix.discovery.DiscoveryClient构造函数-服务注册

    if (this.clientConfig.shouldRegisterWithEureka() && this.clientConfig.shouldEnforceRegistrationAtInit()) {
        try {
            if (!this.register()) {
                throw new IllegalStateException("Registration error at startup. Invalid server response.");
            }
        } catch (Throwable var9) {
            logger.error("Registration error at startup: {}", var9.getMessage());
            throw new IllegalStateException(var9);
        }
    }

    注册失败会抛出异常

    com.netflix.discovery.DiscoveryClient构造函数-启动定时任务

    initScheduledTasks

    private void initScheduledTasks() {
        int renewalIntervalInSecs;
        int expBackOffBound;
        if (this.clientConfig.shouldFetchRegistry()) {
            renewalIntervalInSecs = this.clientConfig.getRegistryFetchIntervalSeconds();
            expBackOffBound = this.clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
            this.cacheRefreshTask = new TimedSupervisorTask("cacheRefresh", this.scheduler, this.cacheRefreshExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.CacheRefreshThread());
            this.scheduler.schedule(this.cacheRefreshTask, (long)renewalIntervalInSecs, TimeUnit.SECONDS);
        }
    
        if (this.clientConfig.shouldRegisterWithEureka()) {
            renewalIntervalInSecs = this.instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
            expBackOffBound = this.clientConfig.getHeartbeatExecutorExponentialBackOffBound();
            logger.info("Starting heartbeat executor: renew interval is: {}", renewalIntervalInSecs);
            this.heartbeatTask = new TimedSupervisorTask("heartbeat", this.scheduler, this.heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.HeartbeatThread());
            this.scheduler.schedule(this.heartbeatTask, (long)renewalIntervalInSecs, TimeUnit.SECONDS);
            this.instanceInfoReplicator = new InstanceInfoReplicator(this, this.instanceInfo, this.clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2);
            this.statusChangeListener = new StatusChangeListener() {
                public String getId() {
                    return "statusChangeListener";
                }
    
                public void notify(StatusChangeEvent statusChangeEvent) {
                    if (InstanceStatus.DOWN != statusChangeEvent.getStatus() && InstanceStatus.DOWN != statusChangeEvent.getPreviousStatus()) {
                        DiscoveryClient.logger.info("Saw local status change event {}", statusChangeEvent);
                    } else {
                        DiscoveryClient.logger.warn("Saw local status change event {}", statusChangeEvent);
                    }
    
                    DiscoveryClient.this.instanceInfoReplicator.onDemandUpdate();
                }
            };
            if (this.clientConfig.shouldOnDemandUpdateStatusChange()) {
                this.applicationInfoManager.registerStatusChangeListener(this.statusChangeListener);
            }
    
            this.instanceInfoReplicator.start(this.clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
        } else {
            logger.info("Not registering with Eureka server per configuration");
        }
    
    }
    • cacheRefreshTask
    • heartbeatTask
    • instanceInfoReplicator

    方法中有statusChangeListener,按需注册是一个事件StatusChangeEvent,状态改变,向server注册

    com.netflix.discovery.DiscoveryClient构造函数-总结

    • 初始化配置
    • 从注册表拉取信息
    • 向server注册自己
    • 初始化定时任务

    拉取注册表信息详解

    查看上面的fetchRegistry(false)

    private boolean fetchRegistry(boolean forceFullRegistryFetch) {
        Stopwatch tracer = this.FETCH_REGISTRY_TIMER.start();
    
        label122: {
            boolean var4;
            try {
                Applications applications = this.getApplications();
                if (!this.clientConfig.shouldDisableDelta() && Strings.isNullOrEmpty(this.clientConfig.getRegistryRefreshSingleVipAddress()) && !forceFullRegistryFetch && applications != null && applications.getRegisteredApplications().size() != 0 && applications.getVersion() != -1L) {
                    this.getAndUpdateDelta(applications);
                } else {
                    logger.info("Disable delta property : {}", this.clientConfig.shouldDisableDelta());
                    logger.info("Single vip registry refresh property : {}", this.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() == -1L);
                    this.getAndStoreFullRegistry();
                }
    
                applications.setAppsHashCode(applications.getReconcileHashCode());
                this.logTotalInstances();
                break label122;
            } catch (Throwable var8) {
                logger.error("DiscoveryClient_{} - was unable to refresh its cache! status = {}", new Object[]{this.appPathIdentifier, var8.getMessage(), var8});
                var4 = false;
            } finally {
                if (tracer != null) {
                    tracer.stop();
                }
    
            }
    
            return var4;
        }
    
        this.onCacheRefreshed();
        this.updateInstanceRemoteStatus();
        return true;
    }

    如果增量式拉取被禁止或第一次拉取注册表

    则进行全量拉取:getAndStoreFullRegistry()

    否则进行增量拉取注册表信息getAndUpdateDelta(applications)

    一般情况,在Eureka client第一次启动,会进行全量拉取。之后的拉取都尽量尝试只进行增量拉取

    拉取服务注册表:

    • 全量拉取:getAndStoreFullRegistry()
    • 增量拉取:getAndUpdateDelta(applications)

    全量拉取

    getAndStoreFullRegistry

    private void getAndStoreFullRegistry() throws Throwable {
        long currentUpdateGeneration = this.fetchRegistryGeneration.get();
        logger.info("Getting all instance registry info from the eureka server");
        Applications apps = null;
        EurekaHttpResponse<Applications> httpResponse = this.clientConfig.getRegistryRefreshSingleVipAddress() == null ? this.eurekaTransport.queryClient.getApplications((String[])this.remoteRegionsRef.get()) : this.eurekaTransport.queryClient.getVip(this.clientConfig.getRegistryRefreshSingleVipAddress(), (String[])this.remoteRegionsRef.get());
        if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
            apps = (Applications)httpResponse.getEntity();
        }
    
        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 (this.fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1L)) {
            this.localRegionApps.set(this.filterAndShuffle(apps));
            logger.debug("Got full registry with apps hashcode {}", apps.getAppsHashCode());
        } else {
            logger.warn("Not updating applications as another thread is updating it already");
        }
    
    }

    有个方法

    this.eurekaTransport.queryClient.getApplications((String[])this.remoteRegionsRef.get())

    其实现类是AbstractJerseyEurekaHttpClient

    • debug出webResource地址为:http://root:root@eureka-7900:7900/eureka/apps/
    • 此端点用于获取server中所有的注册表信息
    • getAndStoreFullRegistry()可能被多个线程同时调用,导致新拉取的注册表被旧的覆盖(如果新拉取的动作设置apps阻塞的情况下)
    • 此时用了AutomicLong来进行版本管理,如果更新时版本不一致,不保存apps

    通过这个判断

    fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)

    如果版本一致,并设置新版本(+1), 接着执行localRegionApps.set(this.filterAndShuffle(apps));

    过滤并洗牌apps

    点开this.filterAndShuffle(apps)实现

    • 继续点apps.shuffleAndIndexInstances
    • 继续点shuffleInstances
    • 继续点application.shuffleAndStoreInstances
    • 继续点_shuffleAndStoreInstances
    • 发现if (filterUpInstances && InstanceStatus.UP != instanceInfo.getStatus())

    只保留状态为UP的服务

    增量拉取

    回到刚才的fetchRegistry方法中,getAndUpdateDelta,增量拉取

    • 通过getDelta方法,看到实际拉取的地址是:apps/delta,如果获取到的delta为空,则全量拉取
    • 通常来讲是3分钟之内注册表的信息变化(在server端判断),获取到delta后,会更新本地注册表
    • 增量式拉取是为了维护client和server端 注册表的一致性,防止本地数据过久,而失效,采用增量式拉取的方式,减少了client和server的通信量
    • client有一个注册表缓存刷新定时器,专门负责维护两者之间的信息同步,但是当增量出现意外时,定时器将执行,全量拉取以更新本地缓存信息

    更新本地注册表方法updateDelta,有一个细节

    if (ActionType.ADDED.equals(instance.getActionType()))

    if (ActionType.ADDED.equals(instance.getActionType())) {
        existingApp = applications.getRegisteredApplications(instance.getAppName());
        if (existingApp == null) {
            applications.addApplication(app);
        }
    
        logger.debug("Added instance {} to the existing apps in region {}", instance.getId(), instanceRegion);
        applications.getRegisteredApplications(instance.getAppName()).addInstance(instance);
    } else if (ActionType.MODIFIED.equals(instance.getActionType())) {
        existingApp = applications.getRegisteredApplications(instance.getAppName());
        if (existingApp == null) {
            applications.addApplication(app);
        }
    
        logger.debug("Modified instance {} to the existing apps ", instance.getId());
        applications.getRegisteredApplications(instance.getAppName()).addInstance(instance);
    } else if (ActionType.DELETED.equals(instance.getActionType())) {
        existingApp = applications.getRegisteredApplications(instance.getAppName());
        if (existingApp != null) {
            logger.debug("Deleted instance {} to the existing apps ", instance.getId());
            existingApp.removeInstance(instance);
            if (existingApp.getInstancesAsIsFromEureka().isEmpty()) {
                applications.removeApplication(existingApp);
            }
        }
    }

    ActionType

    public static enum ActionType {
        ADDED,
        MODIFIED,
        DELETED;
    
        private ActionType() {
        }
    }

    在InstanceInfo instance中有一个instance.getActionType()

    • ADDED和MODIFIED状态的将更新本地注册表applications.addApplication
    • DELETED将从本地剔除掉existingApp.removeInstance(instance)

    服务注册

    好了拉取完eureka server中的注册表了,接着进行服务注册

    回到DiscoveryClient构造函数。

    拉取fetchRegistry完后进行register注册

    boolean register() throws Throwable {
        logger.info("DiscoveryClient_{}: registering service...", this.appPathIdentifier);
    
        EurekaHttpResponse httpResponse;
        try {
            httpResponse = this.eurekaTransport.registrationClient.register(this.instanceInfo);
        } catch (Exception var3) {
            logger.warn("DiscoveryClient_{} - registration failed {}", new Object[]{this.appPathIdentifier, var3.getMessage(), var3});
            throw var3;
        }
    
        if (logger.isInfoEnabled()) {
            logger.info("DiscoveryClient_{} - registration status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
        }
    
        return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();
    }
    • 由于构造函数开始时已经将服务实例元数据封装好了instanceInfo,所以此处之间向server发送instanceInfo
    • 通过方法httpResponse = eurekaTransport.registrationClient.register(instanceInfo)
    • 看到String urlPath = "apps/" + info.getAppName()
    • httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode()
    • 204状态码,则注册成功

    初始化3个定时任务

    看注释初始化3个定时任务

    • client会定时向server发送心跳,维持自己服务租约的有效性,用心跳定时任务实现
    • server中会有不同的服务实例注册进来,一进一出,就需要数据的同步,所以client需要定时从server拉取注册表信息,用缓存定时任务实现
    • client如果有变化,也会及时更新server中自己的信息,用按需注册定时任务实现

    就是这三个定时任务

    initScheduledTasks()方法中,

    • clientConfig.shouldFetchRegistry(),从server拉取注册表信息
    • int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds() 拉取的时间间隔,eureka.client.registryFetchIntervalSeconds进行设置
    • int renewalIntervalInSecs = nstanceInfo.getLeaseInfo().getRenewalIntervalInSecs() 心跳定时器,默认30秒

    new TimedSupervisorTask( "heartbeat", scheduler, heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new HeartbeatThread()

    看到HeartbeatThread线程

    private class HeartbeatThread implements Runnable {
        private HeartbeatThread() {
        }
    
        public void run() {
            if (DiscoveryClient.this.renew()) {
                DiscoveryClient.this.lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
            }
    
        }
    }

    里面是renew()方法

    scheduler.schedule( new TimedSupervisorTask( "cacheRefresh", scheduler, cacheRefreshExecutor, registryFetchIntervalSeconds, TimeUnit.SECONDS, expBackOffBound, new CacheRefreshThread() )

    看到CacheRefreshThread

    class CacheRefreshThread implements Runnable {
        CacheRefreshThread() {
        }
    
        public void run() {
            DiscoveryClient.this.refreshRegistry();
        }
    }

    是用的refreshRegistry,进去发现fetchRegistry

    回到原来讲过的地方

     boolean renew() {
        try {
            EurekaHttpResponse<InstanceInfo> httpResponse = this.eurekaTransport.registrationClient.sendHeartBeat(this.instanceInfo.getAppName(), this.instanceInfo.getId(), this.instanceInfo, (InstanceStatus)null);
            logger.debug("DiscoveryClient_{} - Heartbeat status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
            if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) {
                this.REREGISTER_COUNTER.increment();
                logger.info("DiscoveryClient_{} - Re-registering apps/{}", this.appPathIdentifier, this.instanceInfo.getAppName());
                long timestamp = this.instanceInfo.setIsDirtyWithTime();
                boolean success = this.register();
                if (success) {
                    this.instanceInfo.unsetIsDirty(timestamp);
                }
    
                return success;
            } else {
                return httpResponse.getStatusCode() == Status.OK.getStatusCode();
            }
        } catch (Throwable var5) {
            logger.error("DiscoveryClient_{} - was unable to send heartbeat!", this.appPathIdentifier, var5);
            return false;
        }
    }

    看到如果遇到404,server没有此实例,则重新发起注册

    如果续约成功返回 200. 点sendHeartBeat

    找到接口EurekaHttpClient的实现类AbstractJerseyEurekaHttpClient

     public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id, InstanceInfo info, InstanceStatus overriddenStatus) {
        String urlPath = "apps/" + appName + '/' + id;
        ClientResponse response = null;
    
        EurekaHttpResponse var10;
        try {
            WebResource webResource = this.jerseyClient.resource(this.serviceUrl).path(urlPath).queryParam("status", info.getStatus().toString()).queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString());
            if (overriddenStatus != null) {
                webResource = webResource.queryParam("overriddenstatus", overriddenStatus.name());
            }
    
            Builder requestBuilder = webResource.getRequestBuilder();
            this.addExtraHeaders(requestBuilder);
            response = (ClientResponse)requestBuilder.put(ClientResponse.class);
            EurekaHttpResponseBuilder<InstanceInfo> eurekaResponseBuilder = EurekaHttpResponse.anEurekaHttpResponse(response.getStatus(), InstanceInfo.class).headers(headersOf(response));
            if (response.hasEntity() && !"html".equals(response.getType().getSubtype())) {
                eurekaResponseBuilder.entity(response.getEntity(InstanceInfo.class));
            }
    
            var10 = eurekaResponseBuilder.build();
        } finally {
            if (logger.isDebugEnabled()) {
                logger.debug("Jersey HTTP PUT {}/{}; statusCode={}", new Object[]{this.serviceUrl, urlPath, response == null ? "N/A" : response.getStatus()});
            }
    
            if (response != null) {
                response.close();
            }
    
        }
    
        return var10;
    }

    进去String urlPath = "apps/" + appName + '/' + id;

    还有一个定时任务,按需注册

    当instanceinfo和status发生变化时,需要向server同步,去更新自己在server中的实例信息

    保证server注册表中服务实例信息的有效和可用

    this.instanceInfoReplicator = new InstanceInfoReplicator(this, this.instanceInfo, this.clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2);
    this.statusChangeListener = new StatusChangeListener() {
        public String getId() {
            return "statusChangeListener";
        }
    
        public void notify(StatusChangeEvent statusChangeEvent) {
            if (InstanceStatus.DOWN != statusChangeEvent.getStatus() && InstanceStatus.DOWN != statusChangeEvent.getPreviousStatus()) {
                DiscoveryClient.logger.info("Saw local status change event {}", statusChangeEvent);
            } else {
                DiscoveryClient.logger.warn("Saw local status change event {}", statusChangeEvent);
            }
    
            DiscoveryClient.this.instanceInfoReplicator.onDemandUpdate();
        }
    };
    if (this.clientConfig.shouldOnDemandUpdateStatusChange()) {
        this.applicationInfoManager.registerStatusChangeListener(this.statusChangeListener);
    }
    this.instanceInfoReplicator.start(this.clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());

    此定时任务有2个部分        

    1:定时刷新服务实例信息和检查应用状态的变化,在服务实例信息发生改变的情况下向server重新发起注册

    查看InstanceInfoReplicator

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package com.netflix.discovery;
    
    import com.google.common.util.concurrent.ThreadFactoryBuilder;
    import com.netflix.appinfo.InstanceInfo;
    import com.netflix.discovery.util.RateLimiter;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.ScheduledFuture;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicBoolean;
    import java.util.concurrent.atomic.AtomicReference;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    class InstanceInfoReplicator implements Runnable {
        private static final Logger logger = LoggerFactory.getLogger(InstanceInfoReplicator.class);
        private final DiscoveryClient discoveryClient;
        private final InstanceInfo instanceInfo;
        private final int replicationIntervalSeconds;
        private final ScheduledExecutorService scheduler;
        private final AtomicReference<Future> scheduledPeriodicRef;
        private final AtomicBoolean started;
        private final RateLimiter rateLimiter;
        private final int burstSize;
        private final int allowedRatePerMinute;
    
        InstanceInfoReplicator(DiscoveryClient discoveryClient, InstanceInfo instanceInfo, int replicationIntervalSeconds, int burstSize) {
            this.discoveryClient = discoveryClient;
            this.instanceInfo = instanceInfo;
            this.scheduler = Executors.newScheduledThreadPool(1, (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-InstanceInfoReplicator-%d").setDaemon(true).build());
            this.scheduledPeriodicRef = new AtomicReference();
            this.started = new AtomicBoolean(false);
            this.rateLimiter = new RateLimiter(TimeUnit.MINUTES);
            this.replicationIntervalSeconds = replicationIntervalSeconds;
            this.burstSize = burstSize;
            this.allowedRatePerMinute = 60 * this.burstSize / this.replicationIntervalSeconds;
            logger.info("InstanceInfoReplicator onDemand update allowed rate per min is {}", this.allowedRatePerMinute);
        }
    
        public void start(int initialDelayMs) {
            if (this.started.compareAndSet(false, true)) {
                this.instanceInfo.setIsDirty();
                Future next = this.scheduler.schedule(this, (long)initialDelayMs, TimeUnit.SECONDS);
                this.scheduledPeriodicRef.set(next);
            }
    
        }
    
        public void stop() {
            this.shutdownAndAwaitTermination(this.scheduler);
            this.started.set(false);
        }
    
        private void shutdownAndAwaitTermination(ExecutorService pool) {
            pool.shutdown();
    
            try {
                if (!pool.awaitTermination(3L, TimeUnit.SECONDS)) {
                    pool.shutdownNow();
                }
            } catch (InterruptedException var3) {
                logger.warn("InstanceInfoReplicator stop interrupted");
            }
    
        }
    
        public boolean onDemandUpdate() {
            if (this.rateLimiter.acquire(this.burstSize, (long)this.allowedRatePerMinute)) {
                if (!this.scheduler.isShutdown()) {
                    this.scheduler.submit(new Runnable() {
                        public void run() {
                            InstanceInfoReplicator.logger.debug("Executing on-demand update of local InstanceInfo");
                            Future latestPeriodic = (Future)InstanceInfoReplicator.this.scheduledPeriodicRef.get();
                            if (latestPeriodic != null && !latestPeriodic.isDone()) {
                                InstanceInfoReplicator.logger.debug("Canceling the latest scheduled update, it will be rescheduled at the end of on demand update");
                                latestPeriodic.cancel(false);
                            }
    
                            InstanceInfoReplicator.this.run();
                        }
                    });
                    return true;
                } else {
                    logger.warn("Ignoring onDemand update due to stopped scheduler");
                    return false;
                }
            } else {
                logger.warn("Ignoring onDemand update due to rate limiter");
                return false;
            }
        }
    
        public void run() {
            boolean var6 = false;
    
            ScheduledFuture next;
            label53: {
                try {
                    var6 = true;
                    this.discoveryClient.refreshInstanceInfo();
                    Long dirtyTimestamp = this.instanceInfo.isDirtyWithTime();
                    if (dirtyTimestamp != null) {
                        this.discoveryClient.register();
                        this.instanceInfo.unsetIsDirty(dirtyTimestamp);
                        var6 = false;
                    } else {
                        var6 = false;
                    }
                    break label53;
                } catch (Throwable var7) {
                    logger.warn("There was a problem with the instance info replicator", var7);
                    var6 = false;
                } finally {
                    if (var6) {
                        ScheduledFuture next = this.scheduler.schedule(this, (long)this.replicationIntervalSeconds, TimeUnit.SECONDS);
                        this.scheduledPeriodicRef.set(next);
                    }
                }
    
                next = this.scheduler.schedule(this, (long)this.replicationIntervalSeconds, TimeUnit.SECONDS);
                this.scheduledPeriodicRef.set(next);
                return;
            }
    
            next = this.scheduler.schedule(this, (long)this.replicationIntervalSeconds, TimeUnit.SECONDS);
            this.scheduledPeriodicRef.set(next);
        }
    }

    看到一个方法refreshInstanceInfo点进去,如果有变化,在下次心跳时,同步向server

     void refreshInstanceInfo() {
        this.applicationInfoManager.refreshDataCenterInfoIfRequired();
        this.applicationInfoManager.refreshLeaseInfoIfRequired();
    
        InstanceStatus status;
        try {
            status = this.getHealthCheckHandler().getStatus(this.instanceInfo.getStatus());
        } catch (Exception var3) {
            logger.warn("Exception from healthcheckHandler.getStatus, setting status to DOWN", var3);
            status = InstanceStatus.DOWN;
        }
    
        if (null != status) {
            this.applicationInfoManager.setInstanceStatus(status);
        }
    
    }

    注册状态改变监听器,在应用状态发生变化时,刷新服务实例信息,在服务实例信息发生改变时向server注册

    看这段            

    this.statusChangeListener = new StatusChangeListener() {
        public String getId() {
            return "statusChangeListener";
        }
    
        public void notify(StatusChangeEvent statusChangeEvent) {
            if (InstanceStatus.DOWN != statusChangeEvent.getStatus() && InstanceStatus.DOWN != statusChangeEvent.getPreviousStatus()) {
                DiscoveryClient.logger.info("Saw local status change event {}", statusChangeEvent);
            } else {
                DiscoveryClient.logger.warn("Saw local status change event {}", statusChangeEvent);
            }
    
            DiscoveryClient.this.instanceInfoReplicator.onDemandUpdate();
        }
    };

    如果状态发生改变,调用onDemandUpdate(),点onDemandUpdate进去,看到InstanceInfoReplicator.this.run();    

    一部分自己去检查,一部分等待状态监听事件

    初始化定时任务完成,最后一步启动步骤完成

    接下来就是正常服务于业务。然后消亡       

    服务下线

    服务下线:在应用关闭时,client会向server注销自己,在Discoveryclient销毁前,会执行下面清理方法。

    @PreDestroy
    public synchronized void shutdown() {
        if (this.isShutdown.compareAndSet(false, true)) {
            logger.info("Shutting down DiscoveryClient ...");
            if (this.statusChangeListener != null && this.applicationInfoManager != null) {
                this.applicationInfoManager.unregisterStatusChangeListener(this.statusChangeListener.getId());
            }
    
            this.cancelScheduledTasks();
            if (this.applicationInfoManager != null && this.clientConfig.shouldRegisterWithEureka() && this.clientConfig.shouldUnregisterOnShutdown()) {
                this.applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN);
                this.unregister();
            }
    
            if (this.eurekaTransport != null) {
                this.eurekaTransport.shutdown();
            }
    
            this.heartbeatStalenessMonitor.shutdown();
            this.registryStalenessMonitor.shutdown();
            Monitors.unregisterObject(this);
            logger.info("Completed shut down of DiscoveryClient");
        }
    
    }

    @PreDestroy 表示:在销毁前执行此方法

    • unregisterStatusChangeListener注销监听器
    • cancelScheduledTasks取消定时任务
    • unregister服务下线
    • eurekaTransport.shutdown关闭jersy客户端

    unregister

    void unregister() {
        if (this.eurekaTransport != null && this.eurekaTransport.registrationClient != null) {
            try {
                logger.info("Unregistering ...");
                EurekaHttpResponse<Void> httpResponse = this.eurekaTransport.registrationClient.cancel(this.instanceInfo.getAppName(), this.instanceInfo.getId());
                logger.info("DiscoveryClient_{} - deregister  status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
            } catch (Exception var2) {
                logger.error("DiscoveryClient_{} - de-registration failed{}", new Object[]{this.appPathIdentifier, var2.getMessage(), var2});
            }
        }
    
    }

    AbstractJerseyEurekaHttpClient的cancel方法

    public EurekaHttpResponse<Void> cancel(String appName, String id) {
        String urlPath = "apps/" + appName + '/' + id;
        ClientResponse response = null;
    
        EurekaHttpResponse var6;
        try {
            Builder resourceBuilder = this.jerseyClient.resource(this.serviceUrl).path(urlPath).getRequestBuilder();
            this.addExtraHeaders(resourceBuilder);
            response = (ClientResponse)resourceBuilder.delete(ClientResponse.class);
            var6 = EurekaHttpResponse.anEurekaHttpResponse(response.getStatus()).headers(headersOf(response)).build();
        } finally {
            if (logger.isDebugEnabled()) {
                logger.debug("Jersey HTTP DELETE {}/{}; statusCode={}", new Object[]{this.serviceUrl, urlPath, response == null ? "N/A" : response.getStatus()});
            }
    
            if (response != null) {
                response.close();
            }
    
        }
    
        return var6;
    }

    String urlPath = "apps/" + appName + '/' + id

    看到url和http请求delete方法

    Server的配合

    github地址:https://github.com/Netflix/eureka/wiki/Eureka-REST-operations

    论读书
    睁开眼,书在面前
    闭上眼,书在心里
  • 相关阅读:
    MySql的性能优化
    MySql的备份还原
    MySql的数据目录
    MySql的事务
    MySql的视图
    算法笔记_006:全源最短路径问题【动态规划法】
    算法笔记_005:堆排序问题【变治法】
    算法笔记_004:8枚硬币问题【减治法】
    算法笔记_003:矩阵相乘问题【分治法】
    使用MongoDB和JSP实现一个简单的购物车系统
  • 原文地址:https://www.cnblogs.com/YC-L/p/14479577.html
Copyright © 2011-2022 走看看