Eureka Client客户端源码解析

目录

概况

@EnableEurekaClient

EnableDiscoveryClientImportSelector类

SpringFactoriesLoader类

spring.factories

AutoServiceRegistrationConfiguration类

EurekaClientAutoConfiguration类-Eureka相关bean实例化

CloudEurekaClient类

DiscoveryClient类-初始化instance&任务执行器

register-注册

renew-续约

unregister-下线

CacheRefreshThread-刷新注册信息线程

HeartbeatThread-心跳续约线程

InstanceInfoReplicator-实例信息复制线程

EurekaDiscoveryClientConfiguration类

EurekaClientAutoConfiguration类

EurekaDiscoveryClient类-拉取注册instances

EurekaRibbonClientConfiguration类-实例化robbin client接口


概况

源码版本:2.1.2.RELEASE

eureka-client:1.9.12

@EnableEurekaClient

该注解主要引及EnableDiscoveryClientImportSelector类

EnableDiscoveryClientImportSelector类

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

EnableDiscoveryClientImportSelector类

@Order(2147483547)
public class EnableDiscoveryClientImportSelector extends SpringFactoryImportSelector {
    public EnableDiscoveryClientImportSelector() {
    }
    //选择数据元
    public String[] selectImports(AnnotationMetadata metadata) {
            //1 获取注册到spring的元数据
        String[] imports = super.selectImports(metadata);
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(this.getAnnotationClass().getName(), true));
        boolean autoRegister = attributes.getBoolean("autoRegister");
        //2 autoRegister默认为true,则注册AutoServiceRegistrationConfiguration类到Spring中
        if (autoRegister) {
            List importsList = new ArrayList(Arrays.asList(imports));
            importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
            imports = (String[])importsList.toArray(new String[0]);
        } else {
            Environment env = this.getEnvironment();
            if (ConfigurableEnvironment.class.isInstance(env)) {
                ConfigurableEnvironment configEnv = (ConfigurableEnvironment)env;
                LinkedHashMap 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;
    }

其中1中metadata数据中:

image.png

EnableDiscoveryClientImportSelector类 selectImports(metadata)方法

            public String[] selectImports(AnnotationMetadata metadata) {
        if (!this.isEnabled()) {
            return new String[0];
        } else {
            AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(this.annotationClass.getName(), true));
            Assert.notNull(attributes, "No " + this.getSimpleName() + " attributes found. Is " + metadata.getClassName() + " annotated with @" + this.getSimpleName() + "?");
            //根据annotationClass获取factories
            List factories = new ArrayList(new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(this.annotationClass, this.beanClassLoader)));
            if (factories.isEmpty() && !this.hasDefaultFactory()) {
                throw new IllegalStateException("Annotation @" + this.getSimpleName() + " found, but there are no implementations. Did you forget to include a starter?");
            } else {
                if (factories.size() > 1) {
                    this.log.warn("More than one implementation of @" + this.getSimpleName() + " (now relying on @Conditionals to pick one): " + factories);
                }

                return (String[])factories.toArray(new String[factories.size()]);
            }
        }
    }

 

SpringFactoriesLoader类

loadSpringFactories方法

private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
        //springboot加载后,由于缓存已经存在,此时result不为空,故直接返回。见下图
        MultiValueMap result = (MultiValueMap)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            try {
                // 2.获取所有 META-INF/spring.factories文件
                Enumeration urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();
                            // 3.遍历所有spring.factories文件 
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry entry = (Entry)var6.next();
                        String factoryClassName = ((String)entry.getKey()).trim();
                        String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        int var10 = var9.length;
                                                 // 4.获取properties中key为EnableDiscoveryClient对应的value值列表
                        for(int var11 = 0; var11 < var10; ++var11) {
                            String factoryName = var9[var11];
                            result.add(factoryClassName, factoryName.trim());
                        }
                    }
                }
                                //缓存结果
                cache.put(classLoader, result);
                return result;
            } catch (IOException var13) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
            }
        }
    }

spring.factories

META-INF/spring.factories,其中org.springframework.cloud.client.discovery.EnableDiscoveryClient对应的value值

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration

org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration

但此时,你debugger发现通过SpringFactoriesLoader类loadSpringFactories中直接返回了,而不会去读spring.factories了,所以2中些时只imports中数据为:AutoServiceRegistrationConfiguration.class。

AutoServiceRegistrationConfiguration类

@Configuration
@EnableConfigurationProperties({AutoServiceRegistrationProperties.class})
@ConditionalOnProperty(
    value = {"spring.cloud.service-registry.auto-registration.enabled"},
    matchIfMissing = true
)
public class AutoServiceRegistrationConfiguration {
    public AutoServiceRegistrationConfiguration() {
    }
}

这是因为

由于springboot启动时通过@SpringBootApplication已经加载上述上装载类org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration

Eureka Client客户端源码解析_第1张图片

 

且看该类:原来在此时已经import了EurekaClientAutoConfiguration类

EurekaClientAutoConfiguration类-Eureka相关bean实例化

@Configuration
@EnableConfigurationProperties
@ConditionalOnClass({EurekaClientConfig.class})
@Import({DiscoveryClientOptionalArgsConfiguration.class})
@ConditionalOnBean({Marker.class})
@ConditionalOnProperty(
    value = {"eureka.client.enabled"},
    matchIfMissing = true
)
@ConditionalOnDiscoveryEnabled
@AutoConfigureBefore({NoopDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class})
@AutoConfigureAfter(
    name = {"org.springframework.cloud.autoconfigure.RefreshAutoConfiguration", "org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration", "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"}
)
public class EurekaClientAutoConfiguration {
   ...
    @Bean
    @ConditionalOnMissingBean(
        value = {EurekaInstanceConfig.class},
        search = SearchStrategy.CURRENT
    )
    public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) {
        String hostname = this.getProperty("eureka.instance.hostname");
        boolean preferIpAddress = Boolean.parseBoolean(this.getProperty("eureka.instance.prefer-ip-address"));
        String ipAddress = this.getProperty("eureka.instance.ip-address");
        boolean isSecurePortEnabled = Boolean.parseBoolean(this.getProperty("eureka.instance.secure-port-enabled"));
        String serverContextPath = this.env.getProperty("server.servlet.context-path", "/");
        int serverPort = Integer.valueOf(this.env.getProperty("server.port", this.env.getProperty("port", "8080")));
        Integer managementPort = (Integer)this.env.getProperty("management.server.port", Integer.class);
        String managementContextPath = this.env.getProperty("management.server.servlet.context-path");
        Integer jmxPort = (Integer)this.env.getProperty("com.sun.management.jmxremote.port", Integer.class);
        EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
        instance.setNonSecurePort(serverPort);
        instance.setInstanceId(IdUtils.getDefaultInstanceId(this.env));
        instance.setPreferIpAddress(preferIpAddress);
        instance.setSecurePortEnabled(isSecurePortEnabled);
        if (StringUtils.hasText(ipAddress)) {
            instance.setIpAddress(ipAddress);
        }

        if (isSecurePortEnabled) {
            instance.setSecurePort(serverPort);
        }

        if (StringUtils.hasText(hostname)) {
            instance.setHostname(hostname);
        }

        String statusPageUrlPath = this.getProperty("eureka.instance.status-page-url-path");
        String healthCheckUrlPath = this.getProperty("eureka.instance.health-check-url-path");
        if (StringUtils.hasText(statusPageUrlPath)) {
            instance.setStatusPageUrlPath(statusPageUrlPath);
        }

        if (StringUtils.hasText(healthCheckUrlPath)) {
            instance.setHealthCheckUrlPath(healthCheckUrlPath);
        }

        ManagementMetadata metadata = managementMetadataProvider.get(instance, serverPort, serverContextPath, managementContextPath, managementPort);
        if (metadata != null) {
            instance.setStatusPageUrl(metadata.getStatusPageUrl());
            instance.setHealthCheckUrl(metadata.getHealthCheckUrl());
            if (instance.isSecurePortEnabled()) {
                instance.setSecureHealthCheckUrl(metadata.getSecureHealthCheckUrl());
            }

            Map metadataMap = instance.getMetadataMap();
            metadataMap.computeIfAbsent("management.port", (k) -> {
                return String.valueOf(metadata.getManagementPort());
            });
        } else if (StringUtils.hasText(managementContextPath)) {
            instance.setHealthCheckUrlPath(managementContextPath + instance.getHealthCheckUrlPath());
            instance.setStatusPageUrlPath(managementContextPath + instance.getStatusPageUrlPath());
        }

        this.setupJmxPort(instance, jmxPort);
        return instance;
    }

    private void setupJmxPort(EurekaInstanceConfigBean instance, Integer jmxPort) {
        Map metadataMap = instance.getMetadataMap();
        if (metadataMap.get("jmx.port") == null && jmxPort != null) {
            metadataMap.put("jmx.port", String.valueOf(jmxPort));
        }

    }

    @Bean
    public DiscoveryClient discoveryClient(EurekaClient client, EurekaClientConfig clientConfig) {
        return new EurekaDiscoveryClient(client, clientConfig);
    }

    @Bean
    public EurekaServiceRegistry eurekaServiceRegistry() {
        return new EurekaServiceRegistry();
    }

    @Bean
    @ConditionalOnBean({AutoServiceRegistrationProperties.class})
    @ConditionalOnProperty(
        value = {"spring.cloud.service-registry.auto-registration.enabled"},
        matchIfMissing = true
    )
    public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry registry, EurekaRegistration registration) {
        return new EurekaAutoServiceRegistration(context, registry, registration);
    }

   ....

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @ConditionalOnClass({RefreshScope.class})
    @ConditionalOnBean({RefreshAutoConfiguration.class})
    @ConditionalOnProperty(
        value = {"eureka.client.refresh.enable"},
        havingValue = "true",
        matchIfMissing = true
    )
    @interface ConditionalOnRefreshScope {
    }

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional({EurekaClientAutoConfiguration.OnMissingRefreshScopeCondition.class})
    @interface ConditionalOnMissingRefreshScope {
    }

    @Configuration
    @EurekaClientAutoConfiguration.ConditionalOnRefreshScope
    protected static class RefreshableEurekaClientConfiguration {
        @Autowired
        private ApplicationContext context;
        @Autowired
        private AbstractDiscoveryClientOptionalArgs optionalArgs;

        protected RefreshableEurekaClientConfiguration() {
        }

        @Bean(
            destroyMethod = "shutdown"
        )
        @ConditionalOnMissingBean(
            value = {EurekaClient.class},
            search = SearchStrategy.CURRENT
        )
        @org.springframework.cloud.context.config.annotation.RefreshScope
        @Lazy
        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;
            }
            //创建EurekaClient注册器
            CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager, config, this.optionalArgs, this.context);
            cloudEurekaClient.registerHealthCheck(healthCheckHandler);
            return cloudEurekaClient;
        }

        @Bean
        @ConditionalOnMissingBean(
            value = {ApplicationInfoManager.class},
            search = SearchStrategy.CURRENT
        )
        @org.springframework.cloud.context.config.annotation.RefreshScope
        @Lazy
        public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
            InstanceInfo instanceInfo = (new InstanceInfoFactory()).create(config);
            return new ApplicationInfoManager(config, instanceInfo);
        }

        @Bean
        @org.springframework.cloud.context.config.annotation.RefreshScope
        @ConditionalOnBean({AutoServiceRegistrationProperties.class})
        @ConditionalOnProperty(
            value = {"spring.cloud.service-registry.auto-registration.enabled"},
            matchIfMissing = true
        )
        public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager, @Autowired(required = false) ObjectProvider healthCheckHandler) {
            return EurekaRegistration.builder(instanceConfig).with(applicationInfoManager).with(eurekaClient).with(healthCheckHandler).build();
        }
    }
}

CloudEurekaClient类

public class CloudEurekaClient extends DiscoveryClient {
...
    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);
    }
  }

DiscoveryClient类-初始化instance&任务执行器

启动三个线程

heartbeatExecutor:初始化&启动心跳执行器

cacheRefreshExecutor:初始化&启动获取缓存信息到本地执行器

InstanceInfoReplicator:实例信息复制线程

重要执行逻辑

  • register-注册
  • unregister-下线
  • renew-续约

在执行上续方法同时会通过replicateToPeers()向集群中其它节点发送数据

 

参数说明

eureka.client.refres.enable 实例是否刷新 默认为true

eureka.client.fetchRegistry 是否拉取注册信息 默认为true

eureka.client.registry-fetch-interval-seconds拉取注册信息时间间隔 默认30s

eureka.client.registerWithEureka 是否将实例注册到Eureka上 默认为true

 

eureka.instance.lease-renewal-interval-in-seconds发送心跳时间间隔 默认30s

eureka.instance.lease-expiration-duration-in-seconds心跳超时时间,超时踢出实例 默认90

@Singleton
public class DiscoveryClient implements EurekaClient {
    ...
        public DiscoveryClient(ApplicationInfoManager applicationInfoManager, final EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, EndpointRandomizer randomizer) {
        this(applicationInfoManager, config, args, new Provider() {
            private volatile BackupRegistry backupRegistryInstance;

            public synchronized BackupRegistry get() {
                if (this.backupRegistryInstance == null) {
                    String backupRegistryClassName = config.getBackupRegistryImpl();
                    if (null != backupRegistryClassName) {
                        try {
                            this.backupRegistryInstance = (BackupRegistry)Class.forName(backupRegistryClassName).newInstance();
                            DiscoveryClient.logger.info("Enabled backup registry of type {}", this.backupRegistryInstance.getClass());
                        } catch (InstantiationException var3) {
                            DiscoveryClient.logger.error("Error instantiating BackupRegistry.", var3);
                        } catch (IllegalAccessException var4) {
                            DiscoveryClient.logger.error("Error instantiating BackupRegistry.", var4);
                        } catch (ClassNotFoundException var5) {
                            DiscoveryClient.logger.error("Error instantiating BackupRegistry.", var5);
                        }
                    }

                    if (this.backupRegistryInstance == null) {
                        DiscoveryClient.logger.warn("Using default backup registry implementation which does not do anything.");
                        this.backupRegistryInstance = new NotImplementedRegistryImpl();
                    }
                }

                return this.backupRegistryInstance;
            }
        }, randomizer);
    }

    
    //初始化instance
    @Inject
    DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider backupRegistryProvider, EndpointRandomizer endpointRandomizer) {
        this.RECONCILE_HASH_CODES_MISMATCH = Monitors.newCounter("DiscoveryClient_ReconcileHashCodeMismatch");
        this.FETCH_REGISTRY_TIMER = Monitors.newTimer("DiscoveryClient_FetchRegistry");
        this.REREGISTER_COUNTER = Monitors.newCounter("DiscoveryClient_Reregister");
        this.localRegionApps = new AtomicReference();
        this.fetchRegistryUpdateLock = new ReentrantLock();
        this.healthCheckHandlerRef = new AtomicReference();
        this.remoteRegionVsApps = new ConcurrentHashMap();
        this.lastRemoteInstanceStatus = InstanceStatus.UNKNOWN;
        this.eventListeners = new CopyOnWriteArraySet();
        this.registrySize = 0;
        this.lastSuccessfulRegistryFetchTimestamp = -1L;
        this.lastSuccessfulHeartbeatTimestamp = -1L;
        this.isShutdown = new AtomicBoolean(false);
        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();
        this.clientConfig = config;
        staticClientConfig = this.clientConfig;
        this.transportConfig = config.getTransportConfig();
        this.instanceInfo = myInfo;
        if (myInfo != null) {
            this.appPathIdentifier = this.instanceInfo.getAppName() + "/" + this.instanceInfo.getId();
        } else {
            logger.warn("Setting instanceInfo to a passed in null value");
        }

        this.backupRegistryProvider = backupRegistryProvider;
        this.endpointRandomizer = endpointRandomizer;
        this.urlRandomizer = new InstanceInfoBasedUrlRandomizer(this.instanceInfo);
        this.localRegionApps.set(new Applications());
        this.fetchRegistryGeneration = new AtomicLong(0L);
        this.remoteRegionsToFetch = new AtomicReference(this.clientConfig.fetchRegistryForRemoteRegions());
        this.remoteRegionsRef = new AtomicReference(this.remoteRegionsToFetch.get() == null ? null : ((String)this.remoteRegionsToFetch.get()).split(","));
        //默认为ture 
        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;
        }
        //默认为ture 
        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;
        }

        logger.info("Initializing Eureka in region {}", this.clientConfig.getRegion());
        //shouldFetchRegistry默认为ture
        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 {
            //设置定时调度器
            //线程执行任务均为daemon,当其它线程结束后,该线程自动结束
            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(null);
                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);
            }

            //获取信息失败
            if (this.clientConfig.shouldFetchRegistry() && !this.fetchRegistry(false)) {
                //获取备份信息
                this.fetchRegistryFromBackup();
            }

            if (this.preRegistrationHandler != null) {
                this.preRegistrationHandler.beforeRegistration();
            }

            if (this.clientConfig.shouldRegisterWithEureka() && this.clientConfig.shouldEnforceRegistrationAtInit()) {
                try {
                    当实例允许注册到eureka,则强制注册&初始化
                    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);
                }
            }
            //初始化调度器
            this.initScheduledTasks();

            try {
                Monitors.registerObject(this);
            } catch (Throwable var8) {
                logger.warn("Cannot register timers", var8);
            }

            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());
        }
    }
  ...

    public List getInstancesById(String id) {
        List instancesList = new ArrayList();
        Iterator var3 = this.getApplications().getRegisteredApplications().iterator();

        while(var3.hasNext()) {
            Application app = (Application)var3.next();
            InstanceInfo instanceInfo = app.getByInstanceId(id);
            if (instanceInfo != null) {
                instancesList.add(instanceInfo);
            }
        }

        return instancesList;
    }



    public void registerHealthCheck(HealthCheckHandler healthCheckHandler) {
        if (this.instanceInfo == null) {
            logger.error("Cannot register a healthcheck handler when instance info is null!");
        }

        if (healthCheckHandler != null) {
            this.healthCheckHandlerRef.set(healthCheckHandler);
            if (this.instanceInfoReplicator != null) {
                this.instanceInfoReplicator.onDemandUpdate();
            }
        }

    }

   ...

    public List getInstancesByVipAddress(String vipAddress, boolean secure, @Nullable String region) {
        if (vipAddress == null) {
            throw new IllegalArgumentException("Supplied VIP Address cannot be null");
        } else {
            Applications applications;
            if (this.instanceRegionChecker.isLocalRegion(region)) {
                applications = (Applications)this.localRegionApps.get();
            } else {
                applications = (Applications)this.remoteRegionVsApps.get(region);
                if (null == applications) {
                    logger.debug("No applications are defined for region {}, so returning an empty instance list for vip address {}.", region, vipAddress);
                    return Collections.emptyList();
                }
            }

            return !secure ? applications.getInstancesByVirtualHostName(vipAddress) : applications.getInstancesBySecureVirtualHostName(vipAddress);
        }
    }

    public List getInstancesByVipAddressAndAppName(String vipAddress, String appName, boolean secure) {
        List result = new ArrayList();
        if (vipAddress == null && appName == null) {
            throw new IllegalArgumentException("Supplied VIP Address and application name cannot both be null");
        } else if (vipAddress != null && appName == null) {
            return this.getInstancesByVipAddress(vipAddress, secure);
        } else if (vipAddress == null && appName != null) {
            Application application = this.getApplication(appName);
            if (application != null) {
                result = application.getInstances();
            }

            return (List)result;
        } else {
            Iterator var6 = this.getApplications().getRegisteredApplications().iterator();

            label67:
            while(var6.hasNext()) {
                Application app = (Application)var6.next();
                Iterator var8 = app.getInstances().iterator();

                while(true) {
                    while(true) {
                        String instanceVipAddress;
                        InstanceInfo instance;
                        do {
                            if (!var8.hasNext()) {
                                continue label67;
                            }

                            instance = (InstanceInfo)var8.next();
                            if (secure) {
                                instanceVipAddress = instance.getSecureVipAddress();
                            } else {
                                instanceVipAddress = instance.getVIPAddress();
                            }
                        } while(instanceVipAddress == null);

                        String[] instanceVipAddresses = instanceVipAddress.split(",");
                        String[] var11 = instanceVipAddresses;
                        int var12 = instanceVipAddresses.length;

                        for(int var13 = 0; var13 < var12; ++var13) {
                            String vipAddressFromList = var11[var13];
                            if (vipAddress.equalsIgnoreCase(vipAddressFromList.trim()) && appName.equalsIgnoreCase(instance.getAppName())) {
                                ((List)result).add(instance);
                                break;
                            }
                        }
                    }
                }
            }

            return (List)result;
        }
    }

    public InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure) {
        List instanceInfoList = this.getInstancesByVipAddress(virtualHostname, secure);
        if (instanceInfoList != null && !instanceInfoList.isEmpty()) {
            Applications apps = (Applications)this.localRegionApps.get();
            int index = (int)(apps.getNextIndex(virtualHostname, secure).incrementAndGet() % (long)instanceInfoList.size());
            return (InstanceInfo)instanceInfoList.get(index);
        } else {
            throw new RuntimeException("No matches for the virtual host name :" + virtualHostname);
        }
    }

    public Applications getApplications(String serviceUrl) {
        try {
            EurekaHttpResponse response = this.clientConfig.getRegistryRefreshSingleVipAddress() == null ? this.eurekaTransport.queryClient.getApplications(new String[0]) : this.eurekaTransport.queryClient.getVip(this.clientConfig.getRegistryRefreshSingleVipAddress(), new String[0]);
            if (response.getStatusCode() == Status.OK.getStatusCode()) {
                logger.debug("DiscoveryClient_{} -  refresh status: {}", this.appPathIdentifier, response.getStatusCode());
                return (Applications)response.getEntity();
            }

            logger.error("DiscoveryClient_{} - was unable to refresh its cache! status = {}", this.appPathIdentifier, response.getStatusCode());
        } catch (Throwable var3) {
            logger.error("DiscoveryClient_{} - was unable to refresh its cache! status = {}", new Object[]{this.appPathIdentifier, var3.getMessage(), var3});
        }

        return null;
    }

    //注册
    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();
    }
    
    //续约
    boolean renew() {
        try {
            EurekaHttpResponse 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;
        }
    }

    /** @deprecated */
    @Deprecated
    public List getServiceUrlsFromConfig(String instanceZone, boolean preferSameZone) {
        return EndpointUtils.getServiceUrlsFromConfig(this.clientConfig, instanceZone, preferSameZone);
    }
    
    //下线
    @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();
            logger.info("Completed shut down of DiscoveryClient");
        }

    }
    
    //下线
    void unregister() {
        if (this.eurekaTransport != null && this.eurekaTransport.registrationClient != null) {
            try {
                logger.info("Unregistering ...");
                EurekaHttpResponse 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});
            }
        }

    }

    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;
    }

    private synchronized void updateInstanceRemoteStatus() {
        InstanceStatus currentRemoteInstanceStatus = null;
        if (this.instanceInfo.getAppName() != null) {
            Application app = this.getApplication(this.instanceInfo.getAppName());
            if (app != null) {
                InstanceInfo remoteInstanceInfo = app.getByInstanceId(this.instanceInfo.getId());
                if (remoteInstanceInfo != null) {
                    currentRemoteInstanceStatus = remoteInstanceInfo.getStatus();
                }
            }
        }

        if (currentRemoteInstanceStatus == null) {
            currentRemoteInstanceStatus = InstanceStatus.UNKNOWN;
        }

        if (this.lastRemoteInstanceStatus != currentRemoteInstanceStatus) {
            this.onRemoteStatusChanged(this.lastRemoteInstanceStatus, currentRemoteInstanceStatus);
            this.lastRemoteInstanceStatus = currentRemoteInstanceStatus;
        }

    }

    public InstanceStatus getInstanceRemoteStatus() {
        return this.lastRemoteInstanceStatus;
    }

    private String getReconcileHashCode(Applications applications) {
        TreeMap instanceCountMap = new TreeMap();
        if (this.isFetchingRemoteRegionRegistries()) {
            Iterator var3 = this.remoteRegionVsApps.values().iterator();

            while(var3.hasNext()) {
                Applications remoteApp = (Applications)var3.next();
                remoteApp.populateInstanceCountMap(instanceCountMap);
            }
        }

        applications.populateInstanceCountMap(instanceCountMap);
        return Applications.getReconcileHashCode(instanceCountMap);
    }

    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 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");
        }

    }

    private void getAndUpdateDelta(Applications applications) throws Throwable {
        long currentUpdateGeneration = this.fetchRegistryGeneration.get();
        Applications delta = null;
        EurekaHttpResponse httpResponse = this.eurekaTransport.queryClient.getDelta((String[])this.remoteRegionsRef.get());
        if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
            delta = (Applications)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.");
            this.getAndStoreFullRegistry();
        } else if (this.fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1L)) {
            logger.debug("Got delta update with apps hashcode {}", delta.getAppsHashCode());
            String reconcileHashCode = "";
            if (this.fetchRegistryUpdateLock.tryLock()) {
                try {
                    this.updateDelta(delta);
                    reconcileHashCode = this.getReconcileHashCode(applications);
                } finally {
                    this.fetchRegistryUpdateLock.unlock();
                }
            } else {
                logger.warn("Cannot acquire update lock, aborting getAndUpdateDelta");
            }

            if (!reconcileHashCode.equals(delta.getAppsHashCode()) || this.clientConfig.shouldLogDeltaDiff()) {
                this.reconcileAndLogDifference(delta, reconcileHashCode);
            }
        } 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());
        }

    }

    private void logTotalInstances() {
        if (logger.isDebugEnabled()) {
            int totInstances = 0;

            Application application;
            for(Iterator var2 = this.getApplications().getRegisteredApplications().iterator(); var2.hasNext(); totInstances += application.getInstancesAsIsFromEureka().size()) {
                application = (Application)var2.next();
            }

            logger.debug("The total number of all instances in the client now is {}", totInstances);
        }

    }

    private void reconcileAndLogDifference(Applications delta, String reconcileHashCode) throws Throwable {
        logger.debug("The Reconcile hashcodes do not match, client : {}, server : {}. Getting the full registry", reconcileHashCode, delta.getAppsHashCode());
        this.RECONCILE_HASH_CODES_MISMATCH.increment();
        long currentUpdateGeneration = this.fetchRegistryGeneration.get();
        EurekaHttpResponse httpResponse = this.clientConfig.getRegistryRefreshSingleVipAddress() == null ? this.eurekaTransport.queryClient.getApplications((String[])this.remoteRegionsRef.get()) : this.eurekaTransport.queryClient.getVip(this.clientConfig.getRegistryRefreshSingleVipAddress(), (String[])this.remoteRegionsRef.get());
        Applications serverApps = (Applications)httpResponse.getEntity();
        if (serverApps == null) {
            logger.warn("Cannot fetch full registry from the server; reconciliation failure");
        } else {
            if (this.fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1L)) {
                this.localRegionApps.set(this.filterAndShuffle(serverApps));
                this.getApplications().setVersion(delta.getVersion());
                logger.debug("The Reconcile hashcodes after complete sync up, client : {}, server : {}.", this.getApplications().getReconcileHashCode(), delta.getAppsHashCode());
            } else {
                logger.warn("Not setting the applications map as another thread has advanced the update generation");
            }

        }
    }

    private void updateDelta(Applications delta) {
        int deltaCount = 0;
        Iterator var3 = delta.getRegisteredApplications().iterator();

        while(var3.hasNext()) {
            Application app = (Application)var3.next();
            Iterator var5 = app.getInstances().iterator();

            while(var5.hasNext()) {
                InstanceInfo instance = (InstanceInfo)var5.next();
                Applications applications = this.getApplications();
                String instanceRegion = this.instanceRegionChecker.getInstanceRegion(instance);
                if (!this.instanceRegionChecker.isLocalRegion(instanceRegion)) {
                    Applications remoteApps = (Applications)this.remoteRegionVsApps.get(instanceRegion);
                    if (null == remoteApps) {
                        remoteApps = new Applications();
                        this.remoteRegionVsApps.put(instanceRegion, remoteApps);
                    }

                    applications = remoteApps;
                }

                ++deltaCount;
                Application existingApp;
                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);
                        }
                    }
                }
            }
        }

        logger.debug("The total number of instances fetched by the delta processor : {}", deltaCount);
        this.getApplications().setVersion(delta.getVersion());
        this.getApplications().shuffleInstances(this.clientConfig.shouldFilterOnlyUpInstances());
        var3 = this.remoteRegionVsApps.values().iterator();

        while(var3.hasNext()) {
            Applications applications = (Applications)var3.next();
            applications.setVersion(delta.getVersion());
            applications.shuffleInstances(this.clientConfig.shouldFilterOnlyUpInstances());
        }

    }

    private void initScheduledTasks() {
        int renewalIntervalInSecs;
        int expBackOffBound;
        //获取缓存信息到本地  默认30s 参数:RegistryFetchIntervalSeconds
        if (this.clientConfig.shouldFetchRegistry()) {
            renewalIntervalInSecs = this.clientConfig.getRegistryFetchIntervalSeconds();
            expBackOffBound = this.clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
            this.scheduler.schedule(new TimedSupervisorTask("cacheRefresh", this.scheduler, this.cacheRefreshExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.CacheRefreshThread()), (long)renewalIntervalInSecs, TimeUnit.SECONDS);
        }

        //续约 30s 参数:getRenewalIntervalInSecs
        if (this.clientConfig.shouldRegisterWithEureka()) {
            renewalIntervalInSecs = this.instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
            expBackOffBound = this.clientConfig.getHeartbeatExecutorExponentialBackOffBound();
            logger.info("Starting heartbeat executor: renew interval is: {}", renewalIntervalInSecs);
            this.scheduler.schedule(new TimedSupervisorTask("heartbeat", this.scheduler, this.heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.HeartbeatThread(null)), (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");
        }

    }

    private void cancelScheduledTasks() {
        if (this.instanceInfoReplicator != null) {
            this.instanceInfoReplicator.stop();
        }

        if (this.heartbeatExecutor != null) {
            this.heartbeatExecutor.shutdownNow();
        }

        if (this.cacheRefreshExecutor != null) {
            this.cacheRefreshExecutor.shutdownNow();
        }

        if (this.scheduler != null) {
            this.scheduler.shutdownNow();
        }

    }

    /** @deprecated */
    @Deprecated
    public List getServiceUrlsFromDNS(String instanceZone, boolean preferSameZone) {
        return EndpointUtils.getServiceUrlsFromDNS(this.clientConfig, instanceZone, preferSameZone, this.urlRandomizer);
    }

    /** @deprecated */
    @Deprecated
    public List getDiscoveryServiceUrls(String zone) {
        return EndpointUtils.getDiscoveryServiceUrls(this.clientConfig, zone, this.urlRandomizer);
    }

    /** @deprecated */
    @Deprecated
    public static Set getEC2DiscoveryUrlsFromZone(String dnsName, DiscoveryUrlType type) {
        return EndpointUtils.getEC2DiscoveryUrlsFromZone(dnsName, type);
    }

    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);
        }

    }

    @VisibleForTesting
    InstanceInfoReplicator getInstanceInfoReplicator() {
        return this.instanceInfoReplicator;
    }

    @VisibleForTesting
    InstanceInfo getInstanceInfo() {
        return this.instanceInfo;
    }

    public HealthCheckHandler getHealthCheckHandler() {
        HealthCheckHandler healthCheckHandler = (HealthCheckHandler)this.healthCheckHandlerRef.get();
        if (healthCheckHandler == null) {
            if (null != this.healthCheckHandlerProvider) {
                healthCheckHandler = (HealthCheckHandler)this.healthCheckHandlerProvider.get();
            } else if (null != this.healthCheckCallbackProvider) {
                healthCheckHandler = new HealthCheckCallbackToHandlerBridge((HealthCheckCallback)this.healthCheckCallbackProvider.get());
            }

            if (null == healthCheckHandler) {
                healthCheckHandler = new HealthCheckCallbackToHandlerBridge((HealthCheckCallback)null);
            }

            this.healthCheckHandlerRef.compareAndSet((Object)null, healthCheckHandler);
        }

        return (HealthCheckHandler)this.healthCheckHandlerRef.get();
    }

    @VisibleForTesting
    void refreshRegistry() {
        try {
            boolean isFetchingRemoteRegionRegistries = this.isFetchingRemoteRegionRegistries();
            boolean remoteRegionsModified = false;
            String latestRemoteRegions = this.clientConfig.fetchRegistryForRemoteRegions();
            if (null != latestRemoteRegions) {
                String currentRemoteRegions = (String)this.remoteRegionsToFetch.get();
                if (!latestRemoteRegions.equals(currentRemoteRegions)) {
                    synchronized(this.instanceRegionChecker.getAzToRegionMapper()) {
                        if (this.remoteRegionsToFetch.compareAndSet(currentRemoteRegions, latestRemoteRegions)) {
                            String[] remoteRegions = latestRemoteRegions.split(",");
                            this.remoteRegionsRef.set(remoteRegions);
                            this.instanceRegionChecker.getAzToRegionMapper().setRegionsToFetch(remoteRegions);
                            remoteRegionsModified = true;
                        } else {
                            logger.info("Remote regions to fetch modified concurrently, ignoring change from {} to {}", currentRemoteRegions, latestRemoteRegions);
                        }
                    }
                } else {
                    this.instanceRegionChecker.getAzToRegionMapper().refreshMapping();
                }
            }

            boolean success = this.fetchRegistry(remoteRegionsModified);
            if (success) {
                this.registrySize = ((Applications)this.localRegionApps.get()).size();
                this.lastSuccessfulRegistryFetchTimestamp = System.currentTimeMillis();
            }

            if (logger.isDebugEnabled()) {
                StringBuilder allAppsHashCodes = new StringBuilder();
                allAppsHashCodes.append("Local region apps hashcode: ");
                allAppsHashCodes.append(((Applications)this.localRegionApps.get()).getAppsHashCode());
                allAppsHashCodes.append(", is fetching remote regions? ");
                allAppsHashCodes.append(isFetchingRemoteRegionRegistries);
                Iterator var11 = this.remoteRegionVsApps.entrySet().iterator();

                while(var11.hasNext()) {
                    Entry entry = (Entry)var11.next();
                    allAppsHashCodes.append(", Remote region: ");
                    allAppsHashCodes.append((String)entry.getKey());
                    allAppsHashCodes.append(" , apps hashcode: ");
                    allAppsHashCodes.append(((Applications)entry.getValue()).getAppsHashCode());
                }

                logger.debug("Completed cache refresh task for discovery. All Apps hash code is {} ", allAppsHashCodes);
            }
        } catch (Throwable var9) {
            logger.error("Cannot fetch registry from server", var9);
        }

    }

    private void fetchRegistryFromBackup() {
        try {
            BackupRegistry backupRegistryInstance = this.newBackupRegistryInstance();
            if (null == backupRegistryInstance) {
                backupRegistryInstance = (BackupRegistry)this.backupRegistryProvider.get();
            }

            if (null != backupRegistryInstance) {
                Applications apps = null;
                if (this.isFetchingRemoteRegionRegistries()) {
                    String remoteRegionsStr = (String)this.remoteRegionsToFetch.get();
                    if (null != remoteRegionsStr) {
                        apps = backupRegistryInstance.fetchRegistry(remoteRegionsStr.split(","));
                    }
                } else {
                    apps = backupRegistryInstance.fetchRegistry();
                }

                if (apps != null) {
                    Applications applications = this.filterAndShuffle(apps);
                    applications.setAppsHashCode(applications.getReconcileHashCode());
                    this.localRegionApps.set(applications);
                    this.logTotalInstances();
                    logger.info("Fetched registry successfully from the backup");
                }
            } else {
                logger.warn("No backup registry instance defined & unable to find any discovery servers.");
            }
        } catch (Throwable var4) {
            logger.warn("Cannot fetch applications from apps although backup registry was specified", var4);
        }

    }

    /** @deprecated */
    @Deprecated
    @Nullable
    protected BackupRegistry newBackupRegistryInstance() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        return null;
    }

    private Applications filterAndShuffle(Applications apps) {
        if (apps != null) {
            if (this.isFetchingRemoteRegionRegistries()) {
                Map remoteRegionVsApps = new ConcurrentHashMap();
                apps.shuffleAndIndexInstances(remoteRegionVsApps, this.clientConfig, this.instanceRegionChecker);
                Iterator var3 = remoteRegionVsApps.values().iterator();

                while(var3.hasNext()) {
                    Applications applications = (Applications)var3.next();
                    applications.shuffleInstances(this.clientConfig.shouldFilterOnlyUpInstances());
                }

                this.remoteRegionVsApps = remoteRegionVsApps;
            } else {
                apps.shuffleInstances(this.clientConfig.shouldFilterOnlyUpInstances());
            }
        }

        return apps;
    }

    private boolean isFetchingRemoteRegionRegistries() {
        return null != this.remoteRegionsToFetch.get();
    }

    protected void onRemoteStatusChanged(InstanceStatus oldStatus, InstanceStatus newStatus) {
        this.fireEvent(new StatusChangeEvent(oldStatus, newStatus));
    }

    protected void onCacheRefreshed() {
        this.fireEvent(new CacheRefreshedEvent());
    }

    protected void fireEvent(EurekaEvent event) {
        Iterator var2 = this.eventListeners.iterator();

        while(var2.hasNext()) {
            EurekaEventListener listener = (EurekaEventListener)var2.next();

            try {
                listener.onEvent(event);
            } catch (Exception var5) {
                logger.info("Event {} throw an exception for listener {}", new Object[]{event, listener, var5.getMessage()});
            }
        }

    }

    /** @deprecated */
    @Deprecated
    public static String getZone(InstanceInfo myInfo) {
        String[] availZones = staticClientConfig.getAvailabilityZones(staticClientConfig.getRegion());
        return InstanceInfo.getZone(availZones, myInfo);
    }

    /** @deprecated */
    @Deprecated
    public static String getRegion() {
        String region = staticClientConfig.getRegion();
        if (region == null) {
            region = "default";
        }

        region = region.trim().toLowerCase();
        return region;
    }

    /** @deprecated */
    @Deprecated
    public static List getEurekaServiceUrlsFromConfig(String instanceZone, boolean preferSameZone) {
        return EndpointUtils.getServiceUrlsFromConfig(staticClientConfig, instanceZone, preferSameZone);
    }

    public long getLastSuccessfulHeartbeatTimePeriod() {
        return this.lastSuccessfulHeartbeatTimestamp < 0L ? this.lastSuccessfulHeartbeatTimestamp : System.currentTimeMillis() - this.lastSuccessfulHeartbeatTimestamp;
    }

    public long getLastSuccessfulRegistryFetchTimePeriod() {
        return this.lastSuccessfulRegistryFetchTimestamp < 0L ? this.lastSuccessfulRegistryFetchTimestamp : System.currentTimeMillis() - this.lastSuccessfulRegistryFetchTimestamp;
    }

    @Monitor(
        name = "eurekaClient.registration.lastSuccessfulHeartbeatTimePeriod",
        description = "How much time has passed from last successful heartbeat",
        type = DataSourceType.GAUGE
    )
    private long getLastSuccessfulHeartbeatTimePeriodInternal() {
        long delay = this.clientConfig.shouldRegisterWithEureka() && !this.isShutdown.get() ? this.getLastSuccessfulHeartbeatTimePeriod() : 0L;
        this.heartbeatStalenessMonitor.update(this.computeStalenessMonitorDelay(delay));
        return delay;
    }

    @Monitor(
        name = "eurekaClient.registry.lastSuccessfulRegistryFetchTimePeriod",
        description = "How much time has passed from last successful local registry update",
        type = DataSourceType.GAUGE
    )
    private long getLastSuccessfulRegistryFetchTimePeriodInternal() {
        long delay = this.clientConfig.shouldFetchRegistry() && !this.isShutdown.get() ? this.getLastSuccessfulRegistryFetchTimePeriod() : 0L;
        this.registryStalenessMonitor.update(this.computeStalenessMonitorDelay(delay));
        return delay;
    }

    @Monitor(
        name = "eurekaClient.registry.localRegistrySize",
        description = "Count of instances in the local registry",
        type = DataSourceType.GAUGE
    )
    public int localRegistrySize() {
        return this.registrySize;
    }

    private long computeStalenessMonitorDelay(long delay) {
        return delay < 0L ? System.currentTimeMillis() - this.initTimestampMs : delay;
    }

    class CacheRefreshThread implements Runnable {
        CacheRefreshThread() {
        }

        public void run() {
            DiscoveryClient.this.refreshRegistry();
        }
    }

    private class HeartbeatThread implements Runnable {
        private HeartbeatThread() {
        }

        public void run() {
            if (DiscoveryClient.this.renew()) {
                DiscoveryClient.this.lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
            }

        }
    }


    }

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();
    }
    
    

renew-续约

    //续约
    boolean renew() {
        try {
            EurekaHttpResponse 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;
        }
    }

unregister-下线

    //下线
    @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();
            logger.info("Completed shut down of DiscoveryClient");
        }

    }
    
    //下线
    void unregister() {
        if (this.eurekaTransport != null && this.eurekaTransport.registrationClient != null) {
            try {
                logger.info("Unregistering ...");
                EurekaHttpResponse 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});
            }
        }

    }

    //获取注册信息到本地
    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;
    }

CacheRefreshThread-刷新注册信息线程

DiscoveryClient.this.refreshRegistry():刷新注册信息到本地

    class CacheRefreshThread implements Runnable {
        CacheRefreshThread() {
        }

        public void run() {
            DiscoveryClient.this.refreshRegistry();
        }
    }
    ...
    @VisibleForTesting
    void refreshRegistry() {
        try {
            boolean isFetchingRemoteRegionRegistries = this.isFetchingRemoteRegionRegistries();
            boolean remoteRegionsModified = false;
            String latestRemoteRegions = this.clientConfig.fetchRegistryForRemoteRegions();
            if (null != latestRemoteRegions) {
                String currentRemoteRegions = (String)this.remoteRegionsToFetch.get();
                if (!latestRemoteRegions.equals(currentRemoteRegions)) {
                    synchronized(this.instanceRegionChecker.getAzToRegionMapper()) {
                        if (this.remoteRegionsToFetch.compareAndSet(currentRemoteRegions, latestRemoteRegions)) {
                            String[] remoteRegions = latestRemoteRegions.split(",");
                            this.remoteRegionsRef.set(remoteRegions);
                            this.instanceRegionChecker.getAzToRegionMapper().setRegionsToFetch(remoteRegions);
                            remoteRegionsModified = true;
                        } else {
                            logger.info("Remote regions to fetch modified concurrently, ignoring change from {} to {}", currentRemoteRegions, latestRemoteRegions);
                        }
                    }
                } else {
                    this.instanceRegionChecker.getAzToRegionMapper().refreshMapping();
                }
            }
            //获取注册信息从服务端
            boolean success = this.fetchRegistry(remoteRegionsModified);
            if (success) {
                this.registrySize = ((Applications)this.localRegionApps.get()).size();
                this.lastSuccessfulRegistryFetchTimestamp = System.currentTimeMillis();
            }

            if (logger.isDebugEnabled()) {
                StringBuilder allAppsHashCodes = new StringBuilder();
                allAppsHashCodes.append("Local region apps hashcode: ");
                allAppsHashCodes.append(((Applications)this.localRegionApps.get()).getAppsHashCode());
                allAppsHashCodes.append(", is fetching remote regions? ");
                allAppsHashCodes.append(isFetchingRemoteRegionRegistries);
                Iterator var11 = this.remoteRegionVsApps.entrySet().iterator();

                while(var11.hasNext()) {
                    Entry entry = (Entry)var11.next();
                    allAppsHashCodes.append(", Remote region: ");
                    allAppsHashCodes.append((String)entry.getKey());
                    allAppsHashCodes.append(" , apps hashcode: ");
                    allAppsHashCodes.append(((Applications)entry.getValue()).getAppsHashCode());
                }

                logger.debug("Completed cache refresh task for discovery. All Apps hash code is {} ", allAppsHashCodes);
            }
        } catch (Throwable var9) {
            logger.error("Cannot fetch registry from server", var9);
        }

    }
    
    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;
    }
    
    //增量保存
    private void getAndUpdateDelta(Applications applications) throws Throwable {
        long currentUpdateGeneration = this.fetchRegistryGeneration.get();
        Applications delta = null;
        //发送请求到服务端
        EurekaHttpResponse httpResponse = this.eurekaTransport.queryClient.getDelta((String[])this.remoteRegionsRef.get());
        if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
            delta = (Applications)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.");
            this.getAndStoreFullRegistry();
        } else if (this.fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1L)) {
            logger.debug("Got delta update with apps hashcode {}", delta.getAppsHashCode());
            String reconcileHashCode = "";
            if (this.fetchRegistryUpdateLock.tryLock()) {
                try {
                    this.updateDelta(delta);
                    reconcileHashCode = this.getReconcileHashCode(applications);
                } finally {
                    this.fetchRegistryUpdateLock.unlock();
                }
            } else {
                logger.warn("Cannot acquire update lock, aborting getAndUpdateDelta");
            }

            if (!reconcileHashCode.equals(delta.getAppsHashCode()) || this.clientConfig.shouldLogDeltaDiff()) {
                this.reconcileAndLogDifference(delta, reconcileHashCode);
            }
        } 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());
        }

    }
    
    //全量保存
    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 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");
        }

    }

HeartbeatThread-心跳续约线程

     private class HeartbeatThread implements Runnable {
        private HeartbeatThread() {
        }

        public void run() {
            if (DiscoveryClient.this.renew()) {
                DiscoveryClient.this.lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
            }

        }
    }
    ...
    boolean renew() {
        try {
            //发送心跳请求到服务端
            EurekaHttpResponse 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;
        }
    }
    

InstanceInfoReplicator-实例信息复制线程

class InstanceInfoReplicator implements Runnable {
    ...
    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);
    }
}

EurekaDiscoveryClientConfiguration类

@Configuration
@EnableConfigurationProperties
@ConditionalOnClass({EurekaClientConfig.class})
@ConditionalOnProperty(
    value = {"eureka.client.enabled"},
    matchIfMissing = true
)
@ConditionalOnDiscoveryEnabled       //eueka discovery client配置
public class EurekaDiscoveryClientConfiguration {
    ...
    @Bean
    public EurekaDiscoveryClientConfiguration.Marker eurekaDiscoverClientMarker() {
        return new EurekaDiscoveryClientConfiguration.Marker();
    }

    //依赖spring Listener 
    @Configuration
    @ConditionalOnClass({RefreshScopeRefreshedEvent.class})
    protected static class EurekaClientConfigurationRefresher implements ApplicationListener {
        @Autowired(
            required = false
        )
        private EurekaClient eurekaClient;
        @Autowired(
            required = false
        )
        private EurekaAutoServiceRegistration autoRegistration;

        protected EurekaClientConfigurationRefresher() {
        }

                //自动刷新
        public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
            if (this.eurekaClient != null) {
                this.eurekaClient.getApplications();
            }

            if (this.autoRegistration != null) {
                this.autoRegistration.stop();
                this.autoRegistration.start();
            }

        }
    }

    class Marker {
        Marker() {
        }
    }

    //健康检查
    @Configuration
    @ConditionalOnProperty(
        value = {"eureka.client.healthcheck.enabled"},
        matchIfMissing = false
    )
    protected static class EurekaHealthCheckHandlerConfiguration {
        @Autowired(
            required = false
        )
        private HealthAggregator healthAggregator = new OrderedHealthAggregator();

        protected EurekaHealthCheckHandlerConfiguration() {
        }

        @Bean
        @ConditionalOnMissingBean({HealthCheckHandler.class})
        public EurekaHealthCheckHandler eurekaHealthCheckHandler() {
            return new EurekaHealthCheckHandler(this.healthAggregator);
        }
    }
}

EurekaClientAutoConfiguration类

@Configuration
@EnableConfigurationProperties
@ConditionalOnClass({EurekaClientConfig.class})
@Import({DiscoveryClientOptionalArgsConfiguration.class})
@ConditionalOnBean({Marker.class})
@ConditionalOnProperty(
    value = {"eureka.client.enabled"},
    matchIfMissing = true
)
@ConditionalOnDiscoveryEnabled
@AutoConfigureBefore({NoopDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class})
@AutoConfigureAfter(   //之后在实例EurekaDiscoveryClientConfiguration
    name = {"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;
    }

    @Bean
    public HasFeatures eurekaFeature() {
        return HasFeatures.namedFeature("Eureka Client", EurekaClient.class);
    }

    @Bean
    @ConditionalOnMissingBean(
        value = {EurekaClientConfig.class},
        search = SearchStrategy.CURRENT
    )
    public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) {
        //EurekaClientConfigBean配置初始化
        EurekaClientConfigBean client = new EurekaClientConfigBean();
        if ("bootstrap".equals(this.env.getProperty("spring.config.name"))) {
            client.setRegisterWithEureka(false);
        }

        return client;
    }

    @Bean
    @ConditionalOnMissingBean
    public ManagementMetadataProvider serviceManagementMetadataProvider() {
        return new DefaultManagementMetadataProvider();
    }

    private String getProperty(String property) {
        return this.env.containsProperty(property) ? this.env.getProperty(property) : "";
    }

    @Bean
    @ConditionalOnMissingBean(
        value = {EurekaInstanceConfig.class},
        search = SearchStrategy.CURRENT
    )
    public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) {
        //EurekaInstanceConfigBean实例初始化数据
        String hostname = this.getProperty("eureka.instance.hostname");
        boolean preferIpAddress = Boolean.parseBoolean(this.getProperty("eureka.instance.prefer-ip-address"));
        String ipAddress = this.getProperty("eureka.instance.ip-address");
        boolean isSecurePortEnabled = Boolean.parseBoolean(this.getProperty("eureka.instance.secure-port-enabled"));
        String serverContextPath = this.env.getProperty("server.servlet.context-path", "/");
        int serverPort = Integer.valueOf(this.env.getProperty("server.port", this.env.getProperty("port", "8080")));
        Integer managementPort = (Integer)this.env.getProperty("management.server.port", Integer.class);
        String managementContextPath = this.env.getProperty("management.server.servlet.context-path");
        Integer jmxPort = (Integer)this.env.getProperty("com.sun.management.jmxremote.port", Integer.class);
        EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
        instance.setNonSecurePort(serverPort);
        instance.setInstanceId(IdUtils.getDefaultInstanceId(this.env));
        instance.setPreferIpAddress(preferIpAddress);
        instance.setSecurePortEnabled(isSecurePortEnabled);
        if (StringUtils.hasText(ipAddress)) {
            instance.setIpAddress(ipAddress);
        }

        if (isSecurePortEnabled) {
            instance.setSecurePort(serverPort);
        }

        if (StringUtils.hasText(hostname)) {
            instance.setHostname(hostname);
        }

        String statusPageUrlPath = this.getProperty("eureka.instance.status-page-url-path");
        String healthCheckUrlPath = this.getProperty("eureka.instance.health-check-url-path");
        if (StringUtils.hasText(statusPageUrlPath)) {
            instance.setStatusPageUrlPath(statusPageUrlPath);
        }

        if (StringUtils.hasText(healthCheckUrlPath)) {
            instance.setHealthCheckUrlPath(healthCheckUrlPath);
        }

        ManagementMetadata metadata = managementMetadataProvider.get(instance, serverPort, serverContextPath, managementContextPath, managementPort);
        if (metadata != null) {
            instance.setStatusPageUrl(metadata.getStatusPageUrl());
            instance.setHealthCheckUrl(metadata.getHealthCheckUrl());
            if (instance.isSecurePortEnabled()) {
                instance.setSecureHealthCheckUrl(metadata.getSecureHealthCheckUrl());
            }

            Map metadataMap = instance.getMetadataMap();
            metadataMap.computeIfAbsent("management.port", (k) -> {
                return String.valueOf(metadata.getManagementPort());
            });
        } else if (StringUtils.hasText(managementContextPath)) {
            instance.setHealthCheckUrlPath(managementContextPath + instance.getHealthCheckUrlPath());
            instance.setStatusPageUrlPath(managementContextPath + instance.getStatusPageUrlPath());
        }

        this.setupJmxPort(instance, jmxPort);
        return instance;
    }

    private void setupJmxPort(EurekaInstanceConfigBean instance, Integer jmxPort) {
        Map metadataMap = instance.getMetadataMap();
        if (metadataMap.get("jmx.port") == null && jmxPort != null) {
            metadataMap.put("jmx.port", String.valueOf(jmxPort));
        }

    }

        //EurekaDiscoveryClient实例化
    @Bean
    public DiscoveryClient discoveryClient(EurekaClient client, EurekaClientConfig clientConfig) {
        return new EurekaDiscoveryClient(client, clientConfig);
    }

    //EurekaDiscoveryClient实例化
    @Bean
    public EurekaServiceRegistry eurekaServiceRegistry() {
        return new EurekaServiceRegistry();
    }

    //自动注册
    @Bean
    @ConditionalOnBean({AutoServiceRegistrationProperties.class})
    @ConditionalOnProperty(
        value = {"spring.cloud.service-registry.auto-registration.enabled"},
        matchIfMissing = true
    )
    public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry registry, EurekaRegistration registration) {
        return new EurekaAutoServiceRegistration(context, registry, registration);
    }

    @Configuration
    @ConditionalOnClass({Health.class})
    protected static class EurekaHealthIndicatorConfiguration {
        protected EurekaHealthIndicatorConfiguration() {
        }

        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnEnabledHealthIndicator("eureka")
        public EurekaHealthIndicator eurekaHealthIndicator(EurekaClient eurekaClient, EurekaInstanceConfig instanceConfig, EurekaClientConfig clientConfig) {
            return new EurekaHealthIndicator(eurekaClient, instanceConfig, clientConfig);
        }
    }

    private static class OnMissingRefreshScopeCondition extends AnyNestedCondition {
        OnMissingRefreshScopeCondition() {
            super(ConfigurationPhase.REGISTER_BEAN);
        }

        @ConditionalOnProperty(
            value = {"eureka.client.refresh.enable"},
            havingValue = "false"
        )
        static class OnPropertyDisabled {
            OnPropertyDisabled() {
            }
        }

        @ConditionalOnMissingBean({RefreshAutoConfiguration.class})
        static class MissingScope {
            MissingScope() {
            }
        }

        @ConditionalOnMissingClass({"org.springframework.cloud.context.scope.refresh.RefreshScope"})
        static class MissingClass {
            MissingClass() {
            }
        }
    }

    //自动刷新实例化
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @ConditionalOnClass({RefreshScope.class})
    @ConditionalOnBean({RefreshAutoConfiguration.class})
    @ConditionalOnProperty(
        value = {"eureka.client.refresh.enable"},
        havingValue = "true",
        matchIfMissing = true
    )
    @interface ConditionalOnRefreshScope {
    }

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Conditional({EurekaClientAutoConfiguration.OnMissingRefreshScopeCondition.class})
    @interface ConditionalOnMissingRefreshScope {
    }

    @Configuration
    @EurekaClientAutoConfiguration.ConditionalOnRefreshScope
    protected static class RefreshableEurekaClientConfiguration {
        @Autowired
        private ApplicationContext context;
        @Autowired
        private AbstractDiscoveryClientOptionalArgs optionalArgs;

        protected RefreshableEurekaClientConfiguration() {
        }

        @Bean(
            destroyMethod = "shutdown"
        )
        @ConditionalOnMissingBean(
            value = {EurekaClient.class},
            search = SearchStrategy.CURRENT
        )
        @org.springframework.cloud.context.config.annotation.RefreshScope
        @Lazy
        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;
        }

        @Bean
        @ConditionalOnMissingBean(
            value = {ApplicationInfoManager.class},
            search = SearchStrategy.CURRENT
        )
        @org.springframework.cloud.context.config.annotation.RefreshScope
        @Lazy
        public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
            InstanceInfo instanceInfo = (new InstanceInfoFactory()).create(config);
            return new ApplicationInfoManager(config, instanceInfo);
        }

        @Bean
        @org.springframework.cloud.context.config.annotation.RefreshScope
        @ConditionalOnBean({AutoServiceRegistrationProperties.class})
        @ConditionalOnProperty(
            value = {"spring.cloud.service-registry.auto-registration.enabled"},
            matchIfMissing = true
        )
        public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager, @Autowired(required = false) ObjectProvider healthCheckHandler) {
            return EurekaRegistration.builder(instanceConfig).with(applicationInfoManager).with(eurekaClient).with(healthCheckHandler).build();
        }
    }

    @Configuration
    @EurekaClientAutoConfiguration.ConditionalOnMissingRefreshScope
    protected static class EurekaClientConfiguration {
        @Autowired
        private ApplicationContext context;
        @Autowired
        private AbstractDiscoveryClientOptionalArgs optionalArgs;

        protected EurekaClientConfiguration() {
        }

        @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);
        }

        @Bean
        @ConditionalOnMissingBean(
            value = {ApplicationInfoManager.class},
            search = SearchStrategy.CURRENT
        )
        public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
            InstanceInfo instanceInfo = (new InstanceInfoFactory()).create(config);
            return new ApplicationInfoManager(config, instanceInfo);
        }

        @Bean
        @ConditionalOnBean({AutoServiceRegistrationProperties.class})
        @ConditionalOnProperty(
            value = {"spring.cloud.service-registry.auto-registration.enabled"},
            matchIfMissing = true
        )
        public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager, @Autowired(required = false) ObjectProvider healthCheckHandler) {
            return EurekaRegistration.builder(instanceConfig).with(applicationInfoManager).with(eurekaClient).with(healthCheckHandler).build();
        }
    }
}

EurekaDiscoveryClient类-拉取注册instances

获取注册instances

  public class EurekaDiscoveryClient implements DiscoveryClient {
     public List getInstances(String serviceId) {
        List infos = this.eurekaClient.getInstancesByVipAddress(serviceId, false);
        List instances = new ArrayList();
        Iterator var4 = infos.iterator();

        while(var4.hasNext()) {
            InstanceInfo info = (InstanceInfo)var4.next();
            instances.add(new EurekaDiscoveryClient.EurekaServiceInstance(info));
        }

        return instances;
    }

    public List getServices() {
        Applications applications = this.eurekaClient.getApplications();
        if (applications == null) {
            return Collections.emptyList();
        } else {
            List registered = applications.getRegisteredApplications();
            List names = new ArrayList();
            Iterator var4 = registered.iterator();

            while(var4.hasNext()) {
                Application app = (Application)var4.next();
                if (!app.getInstances().isEmpty()) {
                    names.add(app.getName().toLowerCase());
                }
            }

            return names;
        }
    }
  ...
  }

 

 

 

EurekaRibbonClientConfiguration类-实例化robbin client接口

在spring.factories中自动装配,对EurekaRibbonClientConfiguration实例化,详见eureka+robbin解析

 

@Configuration
public class EurekaRibbonClientConfiguration {
    private static final Log log = LogFactory.getLog(EurekaRibbonClientConfiguration.class);
    @Value("${ribbon.eureka.approximateZoneFromHostname:false}")
    private boolean approximateZoneFromHostname = false;
    @RibbonClientName
    private String serviceId = "client";
   ...
    @Bean
    @ConditionalOnMissingBean
    public IPing ribbonPing(IClientConfig config) {
        if (this.propertiesFactory.isSet(IPing.class, this.serviceId)) {
            return (IPing)this.propertiesFactory.get(IPing.class, config, this.serviceId);
        } else {
            NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
            ping.initWithNiwsConfig(config);
            return ping;
        }
    }

    //实例化ribbonServerList,用于后续与网关通过robbin来获取ServerList列表
    @Bean
    @ConditionalOnMissingBean
    public ServerList ribbonServerList(IClientConfig config, Provider eurekaClientProvider) {
        if (this.propertiesFactory.isSet(ServerList.class, this.serviceId)) {
            return (ServerList)this.propertiesFactory.get(ServerList.class, config, this.serviceId);
        } else {
            DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(config, eurekaClientProvider);
            DomainExtractingServerList serverList = new DomainExtractingServerList(discoveryServerList, config, this.approximateZoneFromHostname);
            return serverList;
        }
    }

    @Bean
    public ServerIntrospector serverIntrospector() {
        return new EurekaServerIntrospector();
    }

        //获取eureka地址
    @PostConstruct
    public void preprocess() {
        String zone = ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone);
        if (this.clientConfig != null && StringUtils.isEmpty(zone)) {
            String availabilityZone;
            if (this.approximateZoneFromHostname && this.eurekaConfig != null) {
                availabilityZone = ZoneUtils.extractApproximateZone(this.eurekaConfig.getHostName(false));
                log.debug("Setting Zone To " + availabilityZone);
                ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone, availabilityZone);
            } else {
                availabilityZone = this.eurekaConfig == null ? null : (String)this.eurekaConfig.getMetadataMap().get("zone");
                if (availabilityZone == null) {
                    String[] zones = this.clientConfig.getAvailabilityZones(this.clientConfig.getRegion());
                    availabilityZone = zones != null && zones.length > 0 ? zones[0] : null;
                }

                if (availabilityZone != null) {
                    ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone, availabilityZone);
                }
            }
        }

        RibbonUtils.initializeRibbonDefaults(this.serviceId);
    }
}

你可能感兴趣的:(源码解析,spring,cloud,源码)