Eureka Client 加载过程以及源码
Eureka架构图
角色分析
服务提供者
是一个eureka client,向Eureka Server注册和更新自己的信息,同时能从Eureka Server注册表中获取到其他服务的信息
服务注册中心
- 提供服务注册和发现的功能
- 每个Eureka Cient向Eureka Server注册自己的信息
- 也可以通过Eureka Server获取到其他服务的信息达到发现和调用其他服务的目的
服务消费者
- 是一个eureka client
- 通过Eureka Server获取注册到其上其他服务的信息
- 从而根据信息找到所需的服务发起远程调用
同步复制
- Eureka Server之间注册表信息的同步复制
- 使Eureka Server集群中不同注册表中服务实例信息保持一致
远程调用
-
服务客户端之间的远程调用
注册
-
Client端向Server端注册自身的元数据以供服务发现
续约
-
通过发送心跳到Server以维持和更新注册表中服务实例元数据的有效性
-
当在一定时长内,Server没有收到Client的心跳信息,将默认服务下线,会把服务实例的信息从注册表中删除
下线
- Client在关闭时主动向Server注销服务实例元数据
- 这时Client的服务实例数据将从Server的注册表中删除
获取注册表
- Client向Server请求注册表信息,用于服务发现,从而发起服务间远程调用
客户端
拉取注册表 从注册表选一个调用
服务端
写个web server
功能
- 定义注册表: Map<name,Map<id,InstanceInfo>>
- 别人可以向我注册自己的信息
- 别人可以从我这里拉取他人的注册信息
- 我和我的同类可以共享注册表
- eureka是用:jersey实现,也是个mvc框架,我们可以自己写个spring boot web实现
@Deprecated,暂时使用,要被废弃
@ImplementedBy,指定的接口实现类
EurekaClient实例化流程
Spring-boot 实例化过程:https://www.cnblogs.com/YC-L/p/14476347.html
eureka client 配置相关类
找到当前项目引入的jar包,spring-cloud-netflix-eureka-client-2.1.2.RELEASE下的 META-INF/spring.factories
此文件中,有如下配置信息
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.netflix.eureka.reactive.EurekaReactiveDiscoveryClientConfiguration,\ org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancerEurekaAutoConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration
- EurekaClientAutoConfiguration,Eureka client自动配置类,负责Eureka client中关键beans的配置和初始化
- RibbonEurekaAutoConfiguration,Ribbon负载均衡相关配置
- EurekaDiscoveryClientConfiguration,配置自动注册和应用的健康检查器
EurekaDiscoveryClientConfiguration.class
注解 @ConditionalOnClass,若这个类存在,就加载这个bean,下面代码中,加载的这个类是EurekaClient
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.cloud.netflix.eureka; import com.netflix.appinfo.HealthCheckHandler; import com.netflix.discovery.EurekaClient; import com.netflix.discovery.EurekaClientConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.health.SimpleStatusAggregator; import org.springframework.boot.actuate.health.StatusAggregator; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled; import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent; import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration( proxyBeanMethods = false ) @EnableConfigurationProperties @ConditionalOnClass({EurekaClientConfig.class}) @ConditionalOnProperty( value = {"eureka.client.enabled"}, matchIfMissing = true ) @ConditionalOnDiscoveryEnabled @ConditionalOnBlockingDiscoveryEnabled public class EurekaDiscoveryClientConfiguration { public EurekaDiscoveryClientConfiguration() { } /** @deprecated */ @Deprecated @Bean public EurekaDiscoveryClientConfiguration.Marker eurekaDiscoverClientMarker() { return new EurekaDiscoveryClientConfiguration.Marker(); } @Bean @ConditionalOnMissingBean public EurekaDiscoveryClient discoveryClient(EurekaClient client, EurekaClientConfig clientConfig) { return new EurekaDiscoveryClient(client, clientConfig); } @Configuration( proxyBeanMethods = false ) @ConditionalOnClass({RefreshScopeRefreshedEvent.class}) protected static class EurekaClientConfigurationRefresher implements ApplicationListener<RefreshScopeRefreshedEvent> { @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(); } } } /** @deprecated */ @Deprecated class Marker { Marker() { } } @Configuration( proxyBeanMethods = false ) @ConditionalOnProperty( value = {"eureka.client.healthcheck.enabled"}, matchIfMissing = false ) protected static class EurekaHealthCheckHandlerConfiguration { @Autowired( required = false ) private StatusAggregator statusAggregator = new SimpleStatusAggregator(); protected EurekaHealthCheckHandlerConfiguration() { } @Bean @ConditionalOnMissingBean({HealthCheckHandler.class}) public EurekaHealthCheckHandler eurekaHealthCheckHandler() { return new EurekaHealthCheckHandler(this.statusAggregator); } } }
DefaultEurekaClientConfig.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.netflix.discovery; import com.google.inject.ImplementedBy; import com.netflix.discovery.shared.transport.EurekaTransportConfig; import java.util.List; import javax.annotation.Nullable; @ImplementedBy(DefaultEurekaClientConfig.class) public interface EurekaClientConfig { int getRegistryFetchIntervalSeconds(); int getInstanceInfoReplicationIntervalSeconds(); int getInitialInstanceInfoReplicationIntervalSeconds(); int getEurekaServiceUrlPollIntervalSeconds(); String getProxyHost(); String getProxyPort(); String getProxyUserName(); String getProxyPassword(); /** @deprecated */ boolean shouldGZipContent(); int getEurekaServerReadTimeoutSeconds(); int getEurekaServerConnectTimeoutSeconds(); String getBackupRegistryImpl(); int getEurekaServerTotalConnections(); int getEurekaServerTotalConnectionsPerHost(); String getEurekaServerURLContext(); String getEurekaServerPort(); String getEurekaServerDNSName(); boolean shouldUseDnsForFetchingServiceUrls(); boolean shouldRegisterWithEureka(); default boolean shouldUnregisterOnShutdown() { return true; } boolean shouldPreferSameZoneEureka(); boolean allowRedirects(); boolean shouldLogDeltaDiff(); boolean shouldDisableDelta(); @Nullable String fetchRegistryForRemoteRegions(); String getRegion(); String[] getAvailabilityZones(String var1); List<String> getEurekaServerServiceUrls(String var1); boolean shouldFilterOnlyUpInstances(); int getEurekaConnectionIdleTimeoutSeconds(); boolean shouldFetchRegistry(); @Nullable String getRegistryRefreshSingleVipAddress(); int getHeartbeatExecutorThreadPoolSize(); int getHeartbeatExecutorExponentialBackOffBound(); int getCacheRefreshExecutorThreadPoolSize(); int getCacheRefreshExecutorExponentialBackOffBound(); String getDollarReplacement(); String getEscapeCharReplacement(); boolean shouldOnDemandUpdateStatusChange(); default boolean shouldEnforceRegistrationAtInit() { return false; } String getEncoderName(); String getDecoderName(); String getClientDataAccept(); String getExperimental(String var1); EurekaTransportConfig getTransportConfig(); }
查看其实现类DefaultEurekaClientConfig.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.netflix.discovery; import com.google.inject.ProvidedBy; import com.netflix.appinfo.EurekaAccept; import com.netflix.config.DynamicPropertyFactory; import com.netflix.config.DynamicStringProperty; import com.netflix.discovery.internal.util.Archaius1Utils; import com.netflix.discovery.providers.DefaultEurekaClientConfigProvider; import com.netflix.discovery.shared.transport.DefaultEurekaTransportConfig; import com.netflix.discovery.shared.transport.EurekaTransportConfig; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.annotation.Nullable; import javax.inject.Singleton; @Singleton @ProvidedBy(DefaultEurekaClientConfigProvider.class) public class DefaultEurekaClientConfig implements EurekaClientConfig { /** @deprecated */ @Deprecated public static final String DEFAULT_NAMESPACE = "eureka."; public static final String DEFAULT_ZONE = "defaultZone"; public static final String URL_SEPARATOR = "\\s*,\\s*"; private final String namespace; private final DynamicPropertyFactory configInstance; private final EurekaTransportConfig transportConfig; public DefaultEurekaClientConfig() { this("eureka"); } public DefaultEurekaClientConfig(String namespace) { this.namespace = namespace.endsWith(".") ? namespace : namespace + "."; this.configInstance = Archaius1Utils.initConfig("eureka-client"); this.transportConfig = new DefaultEurekaTransportConfig(namespace, this.configInstance); } public int getRegistryFetchIntervalSeconds() { return this.configInstance.getIntProperty(this.namespace + "client.refresh.interval", 30).get(); } public int getInstanceInfoReplicationIntervalSeconds() { return this.configInstance.getIntProperty(this.namespace + "appinfo.replicate.interval", 30).get(); } public int getInitialInstanceInfoReplicationIntervalSeconds() { return this.configInstance.getIntProperty(this.namespace + "appinfo.initial.replicate.time", 40).get(); } public int getEurekaServiceUrlPollIntervalSeconds() { return this.configInstance.getIntProperty(this.namespace + "serviceUrlPollIntervalMs", 300000).get() / 1000; } public String getProxyHost() { return this.configInstance.getStringProperty(this.namespace + "eurekaServer.proxyHost", (String)null).get(); } public String getProxyPort() { return this.configInstance.getStringProperty(this.namespace + "eurekaServer.proxyPort", (String)null).get(); } public String getProxyUserName() { return this.configInstance.getStringProperty(this.namespace + "eurekaServer.proxyUserName", (String)null).get(); } public String getProxyPassword() { return this.configInstance.getStringProperty(this.namespace + "eurekaServer.proxyPassword", (String)null).get(); } public boolean shouldGZipContent() { return this.configInstance.getBooleanProperty(this.namespace + "eurekaServer.gzipContent", true).get(); } public int getEurekaServerReadTimeoutSeconds() { return this.configInstance.getIntProperty(this.namespace + "eurekaServer.readTimeout", 8).get(); } public int getEurekaServerConnectTimeoutSeconds() { return this.configInstance.getIntProperty(this.namespace + "eurekaServer.connectTimeout", 5).get(); } public String getBackupRegistryImpl() { return this.configInstance.getStringProperty(this.namespace + "backupregistry", (String)null).get(); } public int getEurekaServerTotalConnections() { return this.configInstance.getIntProperty(this.namespace + "eurekaServer.maxTotalConnections", 200).get(); } public int getEurekaServerTotalConnectionsPerHost() { return this.configInstance.getIntProperty(this.namespace + "eurekaServer.maxConnectionsPerHost", 50).get(); } public String getEurekaServerURLContext() { return this.configInstance.getStringProperty(this.namespace + "eurekaServer.context", this.configInstance.getStringProperty(this.namespace + "context", (String)null).get()).get(); } public String getEurekaServerPort() { return this.configInstance.getStringProperty(this.namespace + "eurekaServer.port", this.configInstance.getStringProperty(this.namespace + "port", (String)null).get()).get(); } public String getEurekaServerDNSName() { return this.configInstance.getStringProperty(this.namespace + "eurekaServer.domainName", this.configInstance.getStringProperty(this.namespace + "domainName", (String)null).get()).get(); } public boolean shouldUseDnsForFetchingServiceUrls() { return this.configInstance.getBooleanProperty(this.namespace + "shouldUseDns", false).get(); } public boolean shouldRegisterWithEureka() { return this.configInstance.getBooleanProperty(this.namespace + "registration.enabled", true).get(); } public boolean shouldUnregisterOnShutdown() { return this.configInstance.getBooleanProperty(this.namespace + "shouldUnregisterOnShutdown", true).get(); } public boolean shouldPreferSameZoneEureka() { return this.configInstance.getBooleanProperty(this.namespace + "preferSameZone", true).get(); } public boolean allowRedirects() { return this.configInstance.getBooleanProperty(this.namespace + "allowRedirects", false).get(); } public boolean shouldLogDeltaDiff() { return this.configInstance.getBooleanProperty(this.namespace + "printDeltaFullDiff", false).get(); } public boolean shouldDisableDelta() { return this.configInstance.getBooleanProperty(this.namespace + "disableDelta", false).get(); } @Nullable public String fetchRegistryForRemoteRegions() { return this.configInstance.getStringProperty(this.namespace + "fetchRemoteRegionsRegistry", (String)null).get(); } public String getRegion() { DynamicStringProperty defaultEurekaRegion = this.configInstance.getStringProperty("eureka.region", "us-east-1"); return this.configInstance.getStringProperty(this.namespace + "region", defaultEurekaRegion.get()).get(); } public String[] getAvailabilityZones(String region) { return this.configInstance.getStringProperty(this.namespace + region + "." + "availabilityZones", "defaultZone").get().split("\\s*,\\s*"); } public List<String> getEurekaServerServiceUrls(String myZone) { String serviceUrls = this.configInstance.getStringProperty(this.namespace + "serviceUrl" + "." + myZone, (String)null).get(); if (serviceUrls == null || serviceUrls.isEmpty()) { serviceUrls = this.configInstance.getStringProperty(this.namespace + "serviceUrl" + ".default", (String)null).get(); } return (List)(serviceUrls != null ? Arrays.asList(serviceUrls.split("\\s*,\\s*")) : new ArrayList()); } public boolean shouldFilterOnlyUpInstances() { return this.configInstance.getBooleanProperty(this.namespace + "shouldFilterOnlyUpInstances", true).get(); } public int getEurekaConnectionIdleTimeoutSeconds() { return this.configInstance.getIntProperty(this.namespace + "eurekaserver.connectionIdleTimeoutInSeconds", 30).get(); } public boolean shouldFetchRegistry() { return this.configInstance.getBooleanProperty(this.namespace + "shouldFetchRegistry", true).get(); } public String getRegistryRefreshSingleVipAddress() { return this.configInstance.getStringProperty(this.namespace + "registryRefreshSingleVipAddress", (String)null).get(); } public int getHeartbeatExecutorThreadPoolSize() { return this.configInstance.getIntProperty(this.namespace + "client.heartbeat.threadPoolSize", 5).get(); } public int getHeartbeatExecutorExponentialBackOffBound() { return this.configInstance.getIntProperty(this.namespace + "client.heartbeat.exponentialBackOffBound", 10).get(); } public int getCacheRefreshExecutorThreadPoolSize() { return this.configInstance.getIntProperty(this.namespace + "client.cacheRefresh.threadPoolSize", 5).get(); } public int getCacheRefreshExecutorExponentialBackOffBound() { return this.configInstance.getIntProperty(this.namespace + "client.cacheRefresh.exponentialBackOffBound", 10).get(); } public String getDollarReplacement() { return this.configInstance.getStringProperty(this.namespace + "dollarReplacement", "_-").get(); } public String getEscapeCharReplacement() { return this.configInstance.getStringProperty(this.namespace + "escapeCharReplacement", "__").get(); } public boolean shouldOnDemandUpdateStatusChange() { return this.configInstance.getBooleanProperty(this.namespace + "shouldOnDemandUpdateStatusChange", true).get(); } public boolean shouldEnforceRegistrationAtInit() { return this.configInstance.getBooleanProperty(this.namespace + "shouldEnforceRegistrationAtInit", false).get(); } public String getEncoderName() { return this.configInstance.getStringProperty(this.namespace + "encoderName", (String)null).get(); } public String getDecoderName() { return this.configInstance.getStringProperty(this.namespace + "decoderName", (String)null).get(); } public String getClientDataAccept() { return this.configInstance.getStringProperty(this.namespace + "clientDataAccept", EurekaAccept.full.name()).get(); } public String getExperimental(String name) { return this.configInstance.getStringProperty(this.namespace + "experimental" + "." + name, (String)null).get(); } public EurekaTransportConfig getTransportConfig() { return this.transportConfig; } }
封装了Eureka Client和Eureka Server交互所需要的配置信息
eurekaClient实现类
DiscoveryClient.class
用来服务发现的客户端接口,是客户端进行服务发现的核心接口,是spring cloud用来进行服务发现的顶级接口,在common中可以看到其地位
在Netflix Eureka和Consul中都有具体的实现类
org.springframework.cloud.client.discovery.DiscoveryClient的类注释:
Represents read operations commonly available to discovery services such as Netflix Eureka or consul.io
代表通用于服务发现的读操作,例如在 eureka或consul中
- 有 String description();//获取实现类的描述
- List<String> getServices();//获取所有服务实例id
- List<ServiceInstance> getInstances(String serviceId);//通过服务id查询服务实例信息列表/p>
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.netflix.discovery; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.inject.Inject; import com.netflix.appinfo.ApplicationInfoManager; import com.netflix.appinfo.HealthCheckCallback; import com.netflix.appinfo.HealthCheckCallbackToHandlerBridge; import com.netflix.appinfo.HealthCheckHandler; import com.netflix.appinfo.InstanceInfo; import com.netflix.appinfo.ApplicationInfoManager.StatusChangeListener; import com.netflix.appinfo.InstanceInfo.ActionType; import com.netflix.appinfo.InstanceInfo.InstanceStatus; import com.netflix.discovery.endpoint.EndpointUtils; import com.netflix.discovery.endpoint.EndpointUtils.DiscoveryUrlType; import com.netflix.discovery.endpoint.EndpointUtils.InstanceInfoBasedUrlRandomizer; import com.netflix.discovery.endpoint.EndpointUtils.ServiceUrlRandomizer; import com.netflix.discovery.shared.Application; import com.netflix.discovery.shared.Applications; import com.netflix.discovery.shared.resolver.ClosableResolver; import com.netflix.discovery.shared.resolver.EndpointRandomizer; import com.netflix.discovery.shared.resolver.ResolverUtils; import com.netflix.discovery.shared.resolver.aws.ApplicationsResolver.ApplicationsSource; import com.netflix.discovery.shared.transport.EurekaHttpClient; import com.netflix.discovery.shared.transport.EurekaHttpClientFactory; import com.netflix.discovery.shared.transport.EurekaHttpClients; import com.netflix.discovery.shared.transport.EurekaHttpResponse; import com.netflix.discovery.shared.transport.EurekaTransportConfig; import com.netflix.discovery.shared.transport.TransportClientFactory; import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient; import com.netflix.discovery.shared.transport.jersey.Jersey1DiscoveryClientOptionalArgs; import com.netflix.discovery.shared.transport.jersey.Jersey1TransportClientFactories; import com.netflix.discovery.shared.transport.jersey.TransportClientFactories; import com.netflix.discovery.util.ThresholdLevelsMetric; import com.netflix.servo.annotations.DataSourceType; import com.netflix.servo.annotations.Monitor; import com.netflix.servo.monitor.Counter; import com.netflix.servo.monitor.Monitors; import com.netflix.servo.monitor.Stopwatch; import com.netflix.servo.monitor.Timer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.TreeMap; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javax.annotation.Nullable; import javax.annotation.PreDestroy; import javax.inject.Provider; import javax.inject.Singleton; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.ws.rs.core.Response.Status; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class DiscoveryClient implements EurekaClient { private static final Logger logger = LoggerFactory.getLogger(DiscoveryClient.class); public static final String HTTP_X_DISCOVERY_ALLOW_REDIRECT = "X-Discovery-AllowRedirect"; private static final String VALUE_DELIMITER = ","; private static final String COMMA_STRING = ","; /** @deprecated */ @Deprecated private static EurekaClientConfig staticClientConfig; private static final String PREFIX = "DiscoveryClient_"; private final Counter RECONCILE_HASH_CODES_MISMATCH; private final Timer FETCH_REGISTRY_TIMER; private final Counter REREGISTER_COUNTER; private final ScheduledExecutorService scheduler; private final ThreadPoolExecutor heartbeatExecutor; private final ThreadPoolExecutor cacheRefreshExecutor; private TimedSupervisorTask cacheRefreshTask; private TimedSupervisorTask heartbeatTask; private final Provider<HealthCheckHandler> healthCheckHandlerProvider; private final Provider<HealthCheckCallback> healthCheckCallbackProvider; private final PreRegistrationHandler preRegistrationHandler; private final AtomicReference<Applications> localRegionApps; private final Lock fetchRegistryUpdateLock; private final AtomicLong fetchRegistryGeneration; private final ApplicationInfoManager applicationInfoManager; private final InstanceInfo instanceInfo; private final AtomicReference<String> remoteRegionsToFetch; private final AtomicReference<String[]> remoteRegionsRef; private final InstanceRegionChecker instanceRegionChecker; private final ServiceUrlRandomizer urlRandomizer; private final EndpointRandomizer endpointRandomizer; private final Provider<BackupRegistry> backupRegistryProvider; private final DiscoveryClient.EurekaTransport eurekaTransport; private final AtomicReference<HealthCheckHandler> healthCheckHandlerRef; private volatile Map<String, Applications> remoteRegionVsApps; private volatile InstanceStatus lastRemoteInstanceStatus; private final CopyOnWriteArraySet<EurekaEventListener> eventListeners; private String appPathIdentifier; private StatusChangeListener statusChangeListener; private InstanceInfoReplicator instanceInfoReplicator; private volatile int registrySize; private volatile long lastSuccessfulRegistryFetchTimestamp; private volatile long lastSuccessfulHeartbeatTimestamp; private final ThresholdLevelsMetric heartbeatStalenessMonitor; private final ThresholdLevelsMetric registryStalenessMonitor; private final AtomicBoolean isShutdown; protected final EurekaClientConfig clientConfig; protected final EurekaTransportConfig transportConfig; private final long initTimestampMs; /** @deprecated */ @Deprecated public DiscoveryClient(InstanceInfo myInfo, EurekaClientConfig config) { this((InstanceInfo)myInfo, config, (DiscoveryClient.DiscoveryClientOptionalArgs)null); } /** @deprecated */ @Deprecated public DiscoveryClient(InstanceInfo myInfo, EurekaClientConfig config, DiscoveryClient.DiscoveryClientOptionalArgs args) { this(ApplicationInfoManager.getInstance(), config, args); } /** @deprecated */ @Deprecated public DiscoveryClient(InstanceInfo myInfo, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args) { this(ApplicationInfoManager.getInstance(), config, args); } public DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config) { this((ApplicationInfoManager)applicationInfoManager, config, (DiscoveryClient.DiscoveryClientOptionalArgs)null); } /** @deprecated */ @Deprecated public DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, DiscoveryClient.DiscoveryClientOptionalArgs args) { this((ApplicationInfoManager)applicationInfoManager, config, (AbstractDiscoveryClientOptionalArgs)args); } public DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args) { this(applicationInfoManager, config, args, ResolverUtils::randomize); } public DiscoveryClient(ApplicationInfoManager applicationInfoManager, final EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, EndpointRandomizer randomizer) { this(applicationInfoManager, config, args, new Provider<BackupRegistry>() { 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); } /** @deprecated */ @Deprecated DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider<BackupRegistry> backupRegistryProvider) { this(applicationInfoManager, config, args, backupRegistryProvider, ResolverUtils::randomize); } @Inject DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider<BackupRegistry> 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(",")); if (config.shouldFetchRegistry()) { this.registryStalenessMonitor = new ThresholdLevelsMetric(this, "eurekaClient.registry.lastUpdateSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L}); } else { this.registryStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC; } if (config.shouldRegisterWithEureka()) { this.heartbeatStalenessMonitor = new ThresholdLevelsMetric(this, "eurekaClient.registration.lastHeartbeatSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L}); } else { this.heartbeatStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC; } logger.info("Initializing Eureka in region {}", this.clientConfig.getRegion()); 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 { try { this.scheduler = Executors.newScheduledThreadPool(2, (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-%d").setDaemon(true).build()); this.heartbeatExecutor = new ThreadPoolExecutor(1, this.clientConfig.getHeartbeatExecutorThreadPoolSize(), 0L, TimeUnit.SECONDS, new SynchronousQueue(), (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-HeartbeatExecutor-%d").setDaemon(true).build()); this.cacheRefreshExecutor = new ThreadPoolExecutor(1, this.clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0L, TimeUnit.SECONDS, new SynchronousQueue(), (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d").setDaemon(true).build()); this.eurekaTransport = new DiscoveryClient.EurekaTransport(); this.scheduleServerEndpointTask(this.eurekaTransport, args); Object azToRegionMapper; if (this.clientConfig.shouldUseDnsForFetchingServiceUrls()) { azToRegionMapper = new DNSBasedAzToRegionMapper(this.clientConfig); } else { azToRegionMapper = new PropertyBasedAzToRegionMapper(this.clientConfig); } if (null != this.remoteRegionsToFetch.get()) { ((AzToRegionMapper)azToRegionMapper).setRegionsToFetch(((String)this.remoteRegionsToFetch.get()).split(",")); } this.instanceRegionChecker = new InstanceRegionChecker((AzToRegionMapper)azToRegionMapper, this.clientConfig.getRegion()); } catch (Throwable var10) { throw new RuntimeException("Failed to initialize DiscoveryClient!", var10); } if (this.clientConfig.shouldFetchRegistry() && !this.fetchRegistry(false)) { this.fetchRegistryFromBackup(); } if (this.preRegistrationHandler != null) { this.preRegistrationHandler.beforeRegistration(); } if (this.clientConfig.shouldRegisterWithEureka() && this.clientConfig.shouldEnforceRegistrationAtInit()) { try { if (!this.register()) { throw new IllegalStateException("Registration error at startup. Invalid server response."); } } catch (Throwable var9) { logger.error("Registration error at startup: {}", var9.getMessage()); throw new IllegalStateException(var9); } } 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()); } } private void scheduleServerEndpointTask(DiscoveryClient.EurekaTransport eurekaTransport, AbstractDiscoveryClientOptionalArgs args) { Collection<?> additionalFilters = args == null ? Collections.emptyList() : args.additionalFilters; EurekaJerseyClient providedJerseyClient = args == null ? null : args.eurekaJerseyClient; TransportClientFactories argsTransportClientFactories = null; if (args != null && args.getTransportClientFactories() != null) { argsTransportClientFactories = args.getTransportClientFactories(); } TransportClientFactories transportClientFactories = argsTransportClientFactories == null ? new Jersey1TransportClientFactories() : argsTransportClientFactories; Optional<SSLContext> sslContext = args == null ? Optional.empty() : args.getSSLContext(); Optional<HostnameVerifier> hostnameVerifier = args == null ? Optional.empty() : args.getHostnameVerifier(); eurekaTransport.transportClientFactory = providedJerseyClient == null ? ((TransportClientFactories)transportClientFactories).newTransportClientFactory(this.clientConfig, (Collection)additionalFilters, this.applicationInfoManager.getInfo(), sslContext, hostnameVerifier) : ((TransportClientFactories)transportClientFactories).newTransportClientFactory((Collection)additionalFilters, providedJerseyClient); ApplicationsSource applicationsSource = new ApplicationsSource() { public Applications getApplications(int stalenessThreshold, TimeUnit timeUnit) { long thresholdInMs = TimeUnit.MILLISECONDS.convert((long)stalenessThreshold, timeUnit); long delay = DiscoveryClient.this.getLastSuccessfulRegistryFetchTimePeriod(); if (delay > thresholdInMs) { DiscoveryClient.logger.info("Local registry is too stale for local lookup. Threshold:{}, actual:{}", thresholdInMs, delay); return null; } else { return (Applications)DiscoveryClient.this.localRegionApps.get(); } } }; eurekaTransport.bootstrapResolver = EurekaHttpClients.newBootstrapResolver(this.clientConfig, this.transportConfig, eurekaTransport.transportClientFactory, this.applicationInfoManager.getInfo(), applicationsSource, this.endpointRandomizer); EurekaHttpClientFactory newQueryClientFactory; EurekaHttpClient newQueryClient; if (this.clientConfig.shouldRegisterWithEureka()) { newQueryClientFactory = null; newQueryClient = null; try { newQueryClientFactory = EurekaHttpClients.registrationClientFactory(eurekaTransport.bootstrapResolver, eurekaTransport.transportClientFactory, this.transportConfig); newQueryClient = newQueryClientFactory.newClient(); } catch (Exception var14) { logger.warn("Transport initialization failure", var14); } eurekaTransport.registrationClientFactory = newQueryClientFactory; eurekaTransport.registrationClient = newQueryClient; } if (this.clientConfig.shouldFetchRegistry()) { newQueryClientFactory = null; newQueryClient = null; try { newQueryClientFactory = EurekaHttpClients.queryClientFactory(eurekaTransport.bootstrapResolver, eurekaTransport.transportClientFactory, this.clientConfig, this.transportConfig, this.applicationInfoManager.getInfo(), applicationsSource, this.endpointRandomizer); newQueryClient = newQueryClientFactory.newClient(); } catch (Exception var13) { logger.warn("Transport initialization failure", var13); } eurekaTransport.queryClientFactory = newQueryClientFactory; eurekaTransport.queryClient = newQueryClient; } } public EurekaClientConfig getEurekaClientConfig() { return this.clientConfig; } public ApplicationInfoManager getApplicationInfoManager() { return this.applicationInfoManager; } public Application getApplication(String appName) { return this.getApplications().getRegisteredApplications(appName); } public Applications getApplications() { return (Applications)this.localRegionApps.get(); } public Applications getApplicationsForARegion(@Nullable String region) { return this.instanceRegionChecker.isLocalRegion(region) ? (Applications)this.localRegionApps.get() : (Applications)this.remoteRegionVsApps.get(region); } public Set<String> getAllKnownRegions() { String localRegion = this.instanceRegionChecker.getLocalRegion(); if (!this.remoteRegionVsApps.isEmpty()) { Set<String> regions = this.remoteRegionVsApps.keySet(); Set<String> toReturn = new HashSet(regions); toReturn.add(localRegion); return toReturn; } else { return Collections.singleton(localRegion); } } public List<InstanceInfo> getInstancesById(String id) { List<InstanceInfo> 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; } /** @deprecated */ @Deprecated public void registerHealthCheckCallback(HealthCheckCallback callback) { if (this.instanceInfo == null) { logger.error("Cannot register a listener for instance info since it is null!"); } if (callback != null) { this.healthCheckHandlerRef.set(new HealthCheckCallbackToHandlerBridge(callback)); } } 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 void registerEventListener(EurekaEventListener eventListener) { this.eventListeners.add(eventListener); } public boolean unregisterEventListener(EurekaEventListener eventListener) { return this.eventListeners.remove(eventListener); } public List<InstanceInfo> getInstancesByVipAddress(String vipAddress, boolean secure) { return this.getInstancesByVipAddress(vipAddress, secure, this.instanceRegionChecker.getLocalRegion()); } public List<InstanceInfo> 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<InstanceInfo> getInstancesByVipAddressAndAppName(String vipAddress, String appName, boolean secure) { List<InstanceInfo> 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<InstanceInfo> 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<Applications> 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<InstanceInfo> httpResponse = this.eurekaTransport.registrationClient.sendHeartBeat(this.instanceInfo.getAppName(), this.instanceInfo.getId(), this.instanceInfo, (InstanceStatus)null); logger.debug("DiscoveryClient_{} - Heartbeat status: {}", this.appPathIdentifier, httpResponse.getStatusCode()); if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) { this.REREGISTER_COUNTER.increment(); logger.info("DiscoveryClient_{} - Re-registering apps/{}", this.appPathIdentifier, this.instanceInfo.getAppName()); long timestamp = this.instanceInfo.setIsDirtyWithTime(); boolean success = this.register(); if (success) { this.instanceInfo.unsetIsDirty(timestamp); } return success; } else { return httpResponse.getStatusCode() == Status.OK.getStatusCode(); } } catch (Throwable var5) { logger.error("DiscoveryClient_{} - was unable to send heartbeat!", this.appPathIdentifier, var5); return false; } } /** @deprecated */ @Deprecated public List<String> 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(); Monitors.unregisterObject(this); logger.info("Completed shut down of DiscoveryClient"); } } void unregister() { if (this.eurekaTransport != null && this.eurekaTransport.registrationClient != null) { try { logger.info("Unregistering ..."); EurekaHttpResponse<Void> httpResponse = this.eurekaTransport.registrationClient.cancel(this.instanceInfo.getAppName(), this.instanceInfo.getId()); logger.info("DiscoveryClient_{} - deregister status: {}", this.appPathIdentifier, httpResponse.getStatusCode()); } catch (Exception var2) { logger.error("DiscoveryClient_{} - de-registration failed{}", new Object[]{this.appPathIdentifier, var2.getMessage(), var2}); } } } 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<String, AtomicInteger> 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<Applications> httpResponse = this.clientConfig.getRegistryRefreshSingleVipAddress() == null ? this.eurekaTransport.queryClient.getApplications((String[])this.remoteRegionsRef.get()) : this.eurekaTransport.queryClient.getVip(this.clientConfig.getRegistryRefreshSingleVipAddress(), (String[])this.remoteRegionsRef.get()); if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) { apps = (Applications)httpResponse.getEntity(); } logger.info("The response status is {}", httpResponse.getStatusCode()); if (apps == null) { logger.error("The application is null for some reason. Not storing this information"); } else if (this.fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1L)) { this.localRegionApps.set(this.filterAndShuffle(apps)); logger.debug("Got full registry with apps hashcode {}", apps.getAppsHashCode()); } else { logger.warn("Not updating applications as another thread is updating it already"); } } private void getAndUpdateDelta(Applications applications) throws Throwable { long currentUpdateGeneration = this.fetchRegistryGeneration.get(); Applications delta = null; EurekaHttpResponse<Applications> 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<Applications> httpResponse = this.clientConfig.getRegistryRefreshSingleVipAddress() == null ? this.eurekaTransport.queryClient.getApplications((String[])this.remoteRegionsRef.get()) : this.eurekaTransport.queryClient.getVip(this.clientConfig.getRegistryRefreshSingleVipAddress(), (String[])this.remoteRegionsRef.get()); 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; if (this.clientConfig.shouldFetchRegistry()) { renewalIntervalInSecs = this.clientConfig.getRegistryFetchIntervalSeconds(); expBackOffBound = this.clientConfig.getCacheRefreshExecutorExponentialBackOffBound(); this.cacheRefreshTask = new TimedSupervisorTask("cacheRefresh", this.scheduler, this.cacheRefreshExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.CacheRefreshThread()); this.scheduler.schedule(this.cacheRefreshTask, (long)renewalIntervalInSecs, TimeUnit.SECONDS); } if (this.clientConfig.shouldRegisterWithEureka()) { renewalIntervalInSecs = this.instanceInfo.getLeaseInfo().getRenewalIntervalInSecs(); expBackOffBound = this.clientConfig.getHeartbeatExecutorExponentialBackOffBound(); logger.info("Starting heartbeat executor: renew interval is: {}", renewalIntervalInSecs); this.heartbeatTask = new TimedSupervisorTask("heartbeat", this.scheduler, this.heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.HeartbeatThread()); this.scheduler.schedule(this.heartbeatTask, (long)renewalIntervalInSecs, TimeUnit.SECONDS); this.instanceInfoReplicator = new InstanceInfoReplicator(this, this.instanceInfo, this.clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2); this.statusChangeListener = new StatusChangeListener() { public String getId() { return "statusChangeListener"; } public void notify(StatusChangeEvent statusChangeEvent) { if (InstanceStatus.DOWN != statusChangeEvent.getStatus() && InstanceStatus.DOWN != statusChangeEvent.getPreviousStatus()) { DiscoveryClient.logger.info("Saw local status change event {}", statusChangeEvent); } else { DiscoveryClient.logger.warn("Saw local status change event {}", statusChangeEvent); } DiscoveryClient.this.instanceInfoReplicator.onDemandUpdate(); } }; if (this.clientConfig.shouldOnDemandUpdateStatusChange()) { this.applicationInfoManager.registerStatusChangeListener(this.statusChangeListener); } this.instanceInfoReplicator.start(this.clientConfig.getInitialInstanceInfoReplicationIntervalSeconds()); } else { logger.info("Not registering with Eureka server per configuration"); } } 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(); } if (this.cacheRefreshTask != null) { this.cacheRefreshTask.cancel(); } if (this.heartbeatTask != null) { this.heartbeatTask.cancel(); } } /** @deprecated */ @Deprecated public List<String> getServiceUrlsFromDNS(String instanceZone, boolean preferSameZone) { return EndpointUtils.getServiceUrlsFromDNS(this.clientConfig, instanceZone, preferSameZone, this.urlRandomizer); } /** @deprecated */ @Deprecated public List<String> getDiscoveryServiceUrls(String zone) { return EndpointUtils.getDiscoveryServiceUrls(this.clientConfig, zone, this.urlRandomizer); } /** @deprecated */ @Deprecated public static Set<String> 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<String, Applications> 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<String, Applications> 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<String> 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(); } } } public static class DiscoveryClientOptionalArgs extends Jersey1DiscoveryClientOptionalArgs { public DiscoveryClientOptionalArgs() { } } private static final class EurekaTransport { private ClosableResolver bootstrapResolver; private TransportClientFactory transportClientFactory; private EurekaHttpClient registrationClient; private EurekaHttpClientFactory registrationClientFactory; private EurekaHttpClient queryClient; private EurekaHttpClientFactory queryClientFactory; private EurekaTransport() { } void shutdown() { if (this.registrationClientFactory != null) { this.registrationClientFactory.shutdown(); } if (this.queryClientFactory != null) { this.queryClientFactory.shutdown(); } if (this.registrationClient != null) { this.registrationClient.shutdown(); } if (this.queryClient != null) { this.queryClient.shutdown(); } if (this.transportClientFactory != null) { this.transportClientFactory.shutdown(); } if (this.bootstrapResolver != null) { this.bootstrapResolver.shutdown(); } } } }
查看private final ApplicationInfoManager applicationInfoManager(应用信息管理器)
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.netflix.appinfo; import com.netflix.appinfo.AmazonInfo.MetaDataKey; import com.netflix.appinfo.InstanceInfo.Builder; import com.netflix.appinfo.InstanceInfo.InstanceStatus; import com.netflix.appinfo.providers.EurekaConfigBasedInstanceInfoProvider; import com.netflix.discovery.StatusChangeEvent; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.inject.Inject; import javax.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class ApplicationInfoManager { private static final Logger logger = LoggerFactory.getLogger(ApplicationInfoManager.class); private static final ApplicationInfoManager.InstanceStatusMapper NO_OP_MAPPER = new ApplicationInfoManager.InstanceStatusMapper() { public InstanceStatus map(InstanceStatus prev) { return prev; } }; private static ApplicationInfoManager instance = new ApplicationInfoManager((EurekaInstanceConfig)null, (InstanceInfo)null, (ApplicationInfoManager.OptionalArgs)null); protected final Map<String, ApplicationInfoManager.StatusChangeListener> listeners; private final ApplicationInfoManager.InstanceStatusMapper instanceStatusMapper; private InstanceInfo instanceInfo; private EurekaInstanceConfig config; @Inject public ApplicationInfoManager(EurekaInstanceConfig config, InstanceInfo instanceInfo, ApplicationInfoManager.OptionalArgs optionalArgs) { this.config = config; this.instanceInfo = instanceInfo; this.listeners = new ConcurrentHashMap(); if (optionalArgs != null) { this.instanceStatusMapper = optionalArgs.getInstanceStatusMapper(); } else { this.instanceStatusMapper = NO_OP_MAPPER; } instance = this; } public ApplicationInfoManager(EurekaInstanceConfig config, ApplicationInfoManager.OptionalArgs optionalArgs) { this(config, (new EurekaConfigBasedInstanceInfoProvider(config)).get(), optionalArgs); } public ApplicationInfoManager(EurekaInstanceConfig config, InstanceInfo instanceInfo) { this(config, instanceInfo, (ApplicationInfoManager.OptionalArgs)null); } /** @deprecated */ @Deprecated public ApplicationInfoManager(EurekaInstanceConfig config) { this(config, (ApplicationInfoManager.OptionalArgs)null); } /** @deprecated */ @Deprecated public static ApplicationInfoManager getInstance() { return instance; } public void initComponent(EurekaInstanceConfig config) { try { this.config = config; this.instanceInfo = (new EurekaConfigBasedInstanceInfoProvider(config)).get(); } catch (Throwable var3) { throw new RuntimeException("Failed to initialize ApplicationInfoManager", var3); } } public InstanceInfo getInfo() { return this.instanceInfo; } public EurekaInstanceConfig getEurekaInstanceConfig() { return this.config; } public void registerAppMetadata(Map<String, String> appMetadata) { this.instanceInfo.registerRuntimeMetadata(appMetadata); } public synchronized void setInstanceStatus(InstanceStatus status) { InstanceStatus next = this.instanceStatusMapper.map(status); if (next != null) { InstanceStatus prev = this.instanceInfo.setStatus(next); if (prev != null) { Iterator var4 = this.listeners.values().iterator(); while(var4.hasNext()) { ApplicationInfoManager.StatusChangeListener listener = (ApplicationInfoManager.StatusChangeListener)var4.next(); try { listener.notify(new StatusChangeEvent(prev, next)); } catch (Exception var7) { logger.warn("failed to notify listener: {}", listener.getId(), var7); } } } } } public void registerStatusChangeListener(ApplicationInfoManager.StatusChangeListener listener) { this.listeners.put(listener.getId(), listener); } public void unregisterStatusChangeListener(String listenerId) { this.listeners.remove(listenerId); } public void refreshDataCenterInfoIfRequired() { String existingAddress = this.instanceInfo.getHostName(); String existingSpotInstanceAction = null; if (this.instanceInfo.getDataCenterInfo() instanceof AmazonInfo) { existingSpotInstanceAction = ((AmazonInfo)this.instanceInfo.getDataCenterInfo()).get(MetaDataKey.spotInstanceAction); } String newAddress; if (this.config instanceof RefreshableInstanceConfig) { newAddress = ((RefreshableInstanceConfig)this.config).resolveDefaultAddress(true); } else { newAddress = this.config.getHostName(true); } String newIp = this.config.getIpAddress(); if (newAddress != null && !newAddress.equals(existingAddress)) { logger.warn("The address changed from : {} => {}", existingAddress, newAddress); this.updateInstanceInfo(newAddress, newIp); } if (this.config.getDataCenterInfo() instanceof AmazonInfo) { String newSpotInstanceAction = ((AmazonInfo)this.config.getDataCenterInfo()).get(MetaDataKey.spotInstanceAction); if (newSpotInstanceAction != null && !newSpotInstanceAction.equals(existingSpotInstanceAction)) { logger.info(String.format("The spot instance termination action changed from: %s => %s", existingSpotInstanceAction, newSpotInstanceAction)); this.updateInstanceInfo((String)null, (String)null); } } } private void updateInstanceInfo(String newAddress, String newIp) { Builder builder = new Builder(this.instanceInfo); if (newAddress != null) { builder.setHostName(newAddress); } if (newIp != null) { builder.setIPAddr(newIp); } builder.setDataCenterInfo(this.config.getDataCenterInfo()); this.instanceInfo.setIsDirty(); } public void refreshLeaseInfoIfRequired() { LeaseInfo leaseInfo = this.instanceInfo.getLeaseInfo(); if (leaseInfo != null) { int currentLeaseDuration = this.config.getLeaseExpirationDurationInSeconds(); int currentLeaseRenewal = this.config.getLeaseRenewalIntervalInSeconds(); if (leaseInfo.getDurationInSecs() != currentLeaseDuration || leaseInfo.getRenewalIntervalInSecs() != currentLeaseRenewal) { LeaseInfo newLeaseInfo = com.netflix.appinfo.LeaseInfo.Builder.newBuilder().setRenewalIntervalInSecs(currentLeaseRenewal).setDurationInSecs(currentLeaseDuration).build(); this.instanceInfo.setLeaseInfo(newLeaseInfo); this.instanceInfo.setIsDirty(); } } } public interface InstanceStatusMapper { InstanceStatus map(InstanceStatus var1); } public interface StatusChangeListener { String getId(); void notify(StatusChangeEvent var1); } public static class OptionalArgs { private ApplicationInfoManager.InstanceStatusMapper instanceStatusMapper; public OptionalArgs() { } @com.google.inject.Inject( optional = true ) public void setInstanceStatusMapper(ApplicationInfoManager.InstanceStatusMapper instanceStatusMapper) { this.instanceStatusMapper = instanceStatusMapper; } ApplicationInfoManager.InstanceStatusMapper getInstanceStatusMapper() { return this.instanceStatusMapper == null ? ApplicationInfoManager.NO_OP_MAPPER : this.instanceStatusMapper; } } }
发现此类的构造函数总有两个属性
- private InstanceInfo instanceInfo
- private EurekaInstanceConfig config
服务实例的信息类InstanceInfo和服务实例配置信息类EurekaInstanceConfig
查看InstanceInfo.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.netflix.appinfo; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonRootName; import com.google.inject.ProvidedBy; import com.netflix.appinfo.AmazonInfo.MetaDataKey; import com.netflix.appinfo.DataCenterInfo.Name; import com.netflix.appinfo.providers.Archaius1VipAddressResolver; import com.netflix.appinfo.providers.EurekaConfigBasedInstanceInfoProvider; import com.netflix.appinfo.providers.VipAddressResolver; import com.netflix.discovery.converters.Auto; import com.netflix.discovery.provider.Serializer; import com.netflix.discovery.util.StringCache; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamOmitField; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ProvidedBy(EurekaConfigBasedInstanceInfoProvider.class) @Serializer("com.netflix.discovery.converters.EntityBodyConverter") @XStreamAlias("instance") @JsonRootName("instance") public class InstanceInfo { private static final String VERSION_UNKNOWN = "unknown"; private static final Logger logger = LoggerFactory.getLogger(InstanceInfo.class); public static final int DEFAULT_PORT = 7001; public static final int DEFAULT_SECURE_PORT = 7002; public static final int DEFAULT_COUNTRY_ID = 1; private volatile String instanceId; private volatile String appName; @Auto private volatile String appGroupName; private volatile String ipAddr; private static final String SID_DEFAULT = "na"; /** @deprecated */ @Deprecated private volatile String sid; private volatile int port; private volatile int securePort; @Auto private volatile String homePageUrl; @Auto private volatile String statusPageUrl; @Auto private volatile String healthCheckUrl; @Auto private volatile String secureHealthCheckUrl; @Auto private volatile String vipAddress; @Auto private volatile String secureVipAddress; @XStreamOmitField private String statusPageRelativeUrl; @XStreamOmitField private String statusPageExplicitUrl; @XStreamOmitField private String healthCheckRelativeUrl; @XStreamOmitField private String healthCheckSecureExplicitUrl; @XStreamOmitField private String vipAddressUnresolved; @XStreamOmitField private String secureVipAddressUnresolved; @XStreamOmitField private String healthCheckExplicitUrl; /** @deprecated */ @Deprecated private volatile int countryId; private volatile boolean isSecurePortEnabled; private volatile boolean isUnsecurePortEnabled; private volatile DataCenterInfo dataCenterInfo; private volatile String hostName; private volatile InstanceInfo.InstanceStatus status; private volatile InstanceInfo.InstanceStatus overriddenStatus; @XStreamOmitField private volatile boolean isInstanceInfoDirty; private volatile LeaseInfo leaseInfo; @Auto private volatile Boolean isCoordinatingDiscoveryServer; @XStreamAlias("metadata") private volatile Map<String, String> metadata; @Auto private volatile Long lastUpdatedTimestamp; @Auto private volatile Long lastDirtyTimestamp; @Auto private volatile InstanceInfo.ActionType actionType; @Auto private volatile String asgName; private String version; private InstanceInfo() { this.sid = "na"; this.port = 7001; this.securePort = 7002; this.countryId = 1; this.isSecurePortEnabled = false; this.isUnsecurePortEnabled = true; this.status = InstanceInfo.InstanceStatus.UP; this.overriddenStatus = InstanceInfo.InstanceStatus.UNKNOWN; this.isInstanceInfoDirty = false; this.isCoordinatingDiscoveryServer = Boolean.FALSE; this.version = "unknown"; this.metadata = new ConcurrentHashMap(); this.lastUpdatedTimestamp = System.currentTimeMillis(); this.lastDirtyTimestamp = this.lastUpdatedTimestamp; } @JsonCreator public InstanceInfo(@JsonProperty("instanceId") String instanceId, @JsonProperty("app") String appName, @JsonProperty("appGroupName") String appGroupName, @JsonProperty("ipAddr") String ipAddr, @JsonProperty("sid") String sid, @JsonProperty("port") InstanceInfo.PortWrapper port, @JsonProperty("securePort") InstanceInfo.PortWrapper securePort, @JsonProperty("homePageUrl") String homePageUrl, @JsonProperty("statusPageUrl") String statusPageUrl, @JsonProperty("healthCheckUrl") String healthCheckUrl, @JsonProperty("secureHealthCheckUrl") String secureHealthCheckUrl, @JsonProperty("vipAddress") String vipAddress, @JsonProperty("secureVipAddress") String secureVipAddress, @JsonProperty("countryId") int countryId, @JsonProperty("dataCenterInfo") DataCenterInfo dataCenterInfo, @JsonProperty("hostName") String hostName, @JsonProperty("status") InstanceInfo.InstanceStatus status, @JsonProperty("overriddenstatus") InstanceInfo.InstanceStatus overriddenStatus, @JsonProperty("overriddenStatus") InstanceInfo.InstanceStatus overriddenStatusAlt, @JsonProperty("leaseInfo") LeaseInfo leaseInfo, @JsonProperty("isCoordinatingDiscoveryServer") Boolean isCoordinatingDiscoveryServer, @JsonProperty("metadata") HashMap<String, String> metadata, @JsonProperty("lastUpdatedTimestamp") Long lastUpdatedTimestamp, @JsonProperty("lastDirtyTimestamp") Long lastDirtyTimestamp, @JsonProperty("actionType") InstanceInfo.ActionType actionType, @JsonProperty("asgName") String asgName) { this.sid = "na"; this.port = 7001; this.securePort = 7002; this.countryId = 1; this.isSecurePortEnabled = false; this.isUnsecurePortEnabled = true; this.status = InstanceInfo.InstanceStatus.UP; this.overriddenStatus = InstanceInfo.InstanceStatus.UNKNOWN; this.isInstanceInfoDirty = false; this.isCoordinatingDiscoveryServer = Boolean.FALSE; this.version = "unknown"; this.instanceId = instanceId; this.sid = sid; this.appName = StringCache.intern(appName); this.appGroupName = StringCache.intern(appGroupName); this.ipAddr = ipAddr; this.port = port == null ? 0 : port.getPort(); this.isUnsecurePortEnabled = port != null && port.isEnabled(); this.securePort = securePort == null ? 0 : securePort.getPort(); this.isSecurePortEnabled = securePort != null && securePort.isEnabled(); this.homePageUrl = homePageUrl; this.statusPageUrl = statusPageUrl; this.healthCheckUrl = healthCheckUrl; this.secureHealthCheckUrl = secureHealthCheckUrl; this.vipAddress = StringCache.intern(vipAddress); this.secureVipAddress = StringCache.intern(secureVipAddress); this.countryId = countryId; this.dataCenterInfo = dataCenterInfo; this.hostName = hostName; this.status = status; this.overriddenStatus = overriddenStatus == null ? overriddenStatusAlt : overriddenStatus; this.leaseInfo = leaseInfo; this.isCoordinatingDiscoveryServer = isCoordinatingDiscoveryServer; this.lastUpdatedTimestamp = lastUpdatedTimestamp; this.lastDirtyTimestamp = lastDirtyTimestamp; this.actionType = actionType; this.asgName = StringCache.intern(asgName); if (metadata == null) { this.metadata = Collections.emptyMap(); } else if (metadata.size() == 1) { this.metadata = this.removeMetadataMapLegacyValues(metadata); } else { this.metadata = metadata; } if (sid == null) { this.sid = "na"; } } public String toString() { return "InstanceInfo [instanceId = " + this.instanceId + ", appName = " + this.appName + ", hostName = " + this.hostName + ", status = " + this.status + ", ipAddr = " + this.ipAddr + ", port = " + this.port + ", securePort = " + this.securePort + ", dataCenterInfo = " + this.dataCenterInfo; } private Map<String, String> removeMetadataMapLegacyValues(Map<String, String> metadata) { if ("java.util.Collections$EmptyMap".equals(metadata.get("@class"))) { metadata.remove("@class"); } else if ("java.util.Collections$EmptyMap".equals(metadata.get("class"))) { metadata.remove("class"); } return metadata; } public InstanceInfo(InstanceInfo ii) { this.sid = "na"; this.port = 7001; this.securePort = 7002; this.countryId = 1; this.isSecurePortEnabled = false; this.isUnsecurePortEnabled = true; this.status = InstanceInfo.InstanceStatus.UP; this.overriddenStatus = InstanceInfo.InstanceStatus.UNKNOWN; this.isInstanceInfoDirty = false; this.isCoordinatingDiscoveryServer = Boolean.FALSE; this.version = "unknown"; this.instanceId = ii.instanceId; this.appName = ii.appName; this.appGroupName = ii.appGroupName; this.ipAddr = ii.ipAddr; this.sid = ii.sid; this.port = ii.port; this.securePort = ii.securePort; this.homePageUrl = ii.homePageUrl; this.statusPageUrl = ii.statusPageUrl; this.healthCheckUrl = ii.healthCheckUrl; this.secureHealthCheckUrl = ii.secureHealthCheckUrl; this.vipAddress = ii.vipAddress; this.secureVipAddress = ii.secureVipAddress; this.statusPageRelativeUrl = ii.statusPageRelativeUrl; this.statusPageExplicitUrl = ii.statusPageExplicitUrl; this.healthCheckRelativeUrl = ii.healthCheckRelativeUrl; this.healthCheckSecureExplicitUrl = ii.healthCheckSecureExplicitUrl; this.vipAddressUnresolved = ii.vipAddressUnresolved; this.secureVipAddressUnresolved = ii.secureVipAddressUnresolved; this.healthCheckExplicitUrl = ii.healthCheckExplicitUrl; this.countryId = ii.countryId; this.isSecurePortEnabled = ii.isSecurePortEnabled; this.isUnsecurePortEnabled = ii.isUnsecurePortEnabled; this.dataCenterInfo = ii.dataCenterInfo; this.hostName = ii.hostName; this.status = ii.status; this.overriddenStatus = ii.overriddenStatus; this.isInstanceInfoDirty = ii.isInstanceInfoDirty; this.leaseInfo = ii.leaseInfo; this.isCoordinatingDiscoveryServer = ii.isCoordinatingDiscoveryServer; this.metadata = ii.metadata; this.lastUpdatedTimestamp = ii.lastUpdatedTimestamp; this.lastDirtyTimestamp = ii.lastDirtyTimestamp; this.actionType = ii.actionType; this.asgName = ii.asgName; this.version = ii.version; } public int hashCode() { String id = this.getId(); return id == null ? 31 : id.hashCode() + 31; } public boolean equals(Object obj) { if (this == obj) { return true; } else if (obj == null) { return false; } else if (this.getClass() != obj.getClass()) { return false; } else { InstanceInfo other = (InstanceInfo)obj; String id = this.getId(); if (id == null) { if (other.getId() != null) { return false; } } else if (!id.equals(other.getId())) { return false; } return true; } } public String getInstanceId() { return this.instanceId; } @JsonProperty("app") public String getAppName() { return this.appName; } public String getAppGroupName() { return this.appGroupName; } public String getHostName() { return this.hostName; } /** @deprecated */ @Deprecated public void setSID(String sid) { this.sid = sid; this.setIsDirty(); } /** @deprecated */ @JsonProperty("sid") @Deprecated public String getSID() { return this.sid; } @JsonIgnore public String getId() { if (this.instanceId != null && !this.instanceId.isEmpty()) { return this.instanceId; } else { if (this.dataCenterInfo instanceof UniqueIdentifier) { String uniqueId = ((UniqueIdentifier)this.dataCenterInfo).getId(); if (uniqueId != null && !uniqueId.isEmpty()) { return uniqueId; } } return this.hostName; } } @JsonProperty("ipAddr") public String getIPAddr() { return this.ipAddr; } @JsonIgnore public int getPort() { return this.port; } public InstanceInfo.InstanceStatus getStatus() { return this.status; } public InstanceInfo.InstanceStatus getOverriddenStatus() { return this.overriddenStatus; } public DataCenterInfo getDataCenterInfo() { return this.dataCenterInfo; } public LeaseInfo getLeaseInfo() { return this.leaseInfo; } public void setLeaseInfo(LeaseInfo info) { this.leaseInfo = info; } public Map<String, String> getMetadata() { return this.metadata; } /** @deprecated */ @Deprecated public int getCountryId() { return this.countryId; } @JsonIgnore public int getSecurePort() { return this.securePort; } @JsonIgnore public boolean isPortEnabled(InstanceInfo.PortType type) { return type == InstanceInfo.PortType.SECURE ? this.isSecurePortEnabled : this.isUnsecurePortEnabled; } public long getLastUpdatedTimestamp() { return this.lastUpdatedTimestamp; } public void setLastUpdatedTimestamp() { this.lastUpdatedTimestamp = System.currentTimeMillis(); } public String getHomePageUrl() { return this.homePageUrl; } public String getStatusPageUrl() { return this.statusPageUrl; } @JsonIgnore public Set<String> getHealthCheckUrls() { Set<String> healthCheckUrlSet = new LinkedHashSet(); if (this.isUnsecurePortEnabled && this.healthCheckUrl != null && !this.healthCheckUrl.isEmpty()) { healthCheckUrlSet.add(this.healthCheckUrl); } if (this.isSecurePortEnabled && this.secureHealthCheckUrl != null && !this.secureHealthCheckUrl.isEmpty()) { healthCheckUrlSet.add(this.secureHealthCheckUrl); } return healthCheckUrlSet; } public String getHealthCheckUrl() { return this.healthCheckUrl; } public String getSecureHealthCheckUrl() { return this.secureHealthCheckUrl; } @JsonProperty("vipAddress") public String getVIPAddress() { return this.vipAddress; } public String getSecureVipAddress() { return this.secureVipAddress; } public Long getLastDirtyTimestamp() { return this.lastDirtyTimestamp; } public void setLastDirtyTimestamp(Long lastDirtyTimestamp) { this.lastDirtyTimestamp = lastDirtyTimestamp; } public synchronized InstanceInfo.InstanceStatus setStatus(InstanceInfo.InstanceStatus status) { if (this.status != status) { InstanceInfo.InstanceStatus prev = this.status; this.status = status; this.setIsDirty(); return prev; } else { return null; } } public synchronized void setStatusWithoutDirty(InstanceInfo.InstanceStatus status) { if (this.status != status) { this.status = status; } } public synchronized void setOverriddenStatus(InstanceInfo.InstanceStatus status) { if (this.overriddenStatus != status) { this.overriddenStatus = status; } } @JsonIgnore public boolean isDirty() { return this.isInstanceInfoDirty; } public synchronized Long isDirtyWithTime() { return this.isInstanceInfoDirty ? this.lastDirtyTimestamp : null; } /** @deprecated */ @Deprecated public synchronized void setIsDirty(boolean isDirty) { if (isDirty) { this.setIsDirty(); } else { this.isInstanceInfoDirty = false; } } public synchronized void setIsDirty() { this.isInstanceInfoDirty = true; this.lastDirtyTimestamp = System.currentTimeMillis(); } public synchronized long setIsDirtyWithTime() { this.setIsDirty(); return this.lastDirtyTimestamp; } public synchronized void unsetIsDirty(long unsetDirtyTimestamp) { if (this.lastDirtyTimestamp <= unsetDirtyTimestamp) { this.isInstanceInfoDirty = false; } } public void setIsCoordinatingDiscoveryServer() { String instanceId = this.getId(); if (instanceId != null && instanceId.equals(ApplicationInfoManager.getInstance().getInfo().getId())) { this.isCoordinatingDiscoveryServer = Boolean.TRUE; } else { this.isCoordinatingDiscoveryServer = Boolean.FALSE; } } @JsonProperty("isCoordinatingDiscoveryServer") public Boolean isCoordinatingDiscoveryServer() { return this.isCoordinatingDiscoveryServer; } public InstanceInfo.ActionType getActionType() { return this.actionType; } public void setActionType(InstanceInfo.ActionType actionType) { this.actionType = actionType; } @JsonProperty("asgName") public String getASGName() { return this.asgName; } /** @deprecated */ @Deprecated @JsonIgnore public String getVersion() { return this.version; } synchronized void registerRuntimeMetadata(Map<String, String> runtimeMetadata) { this.metadata.putAll(runtimeMetadata); this.setIsDirty(); } public static String getZone(String[] availZones, InstanceInfo myInfo) { String instanceZone = availZones != null && availZones.length != 0 ? availZones[0] : "default"; if (myInfo != null && myInfo.getDataCenterInfo().getName() == Name.Amazon) { String awsInstanceZone = ((AmazonInfo)myInfo.getDataCenterInfo()).get(MetaDataKey.availabilityZone); if (awsInstanceZone != null) { instanceZone = awsInstanceZone; } } return instanceZone; } public static enum ActionType { ADDED, MODIFIED, DELETED; private ActionType() { } } public static final class Builder { private static final String COLON = ":"; private static final String HTTPS_PROTOCOL = "https://"; private static final String HTTP_PROTOCOL = "http://"; private final Function<String, String> intern; @XStreamOmitField private InstanceInfo result; @XStreamOmitField private final VipAddressResolver vipAddressResolver; private String namespace; private Builder(InstanceInfo result, VipAddressResolver vipAddressResolver, Function<String, String> intern) { this.vipAddressResolver = vipAddressResolver; this.result = result; this.intern = intern != null ? intern : StringCache::intern; } public Builder(InstanceInfo instanceInfo) { this(instanceInfo, InstanceInfo.Builder.LazyHolder.DEFAULT_VIP_ADDRESS_RESOLVER, (Function)null); } public static InstanceInfo.Builder newBuilder() { return new InstanceInfo.Builder(new InstanceInfo(), InstanceInfo.Builder.LazyHolder.DEFAULT_VIP_ADDRESS_RESOLVER, (Function)null); } public static InstanceInfo.Builder newBuilder(Function<String, String> intern) { return new InstanceInfo.Builder(new InstanceInfo(), InstanceInfo.Builder.LazyHolder.DEFAULT_VIP_ADDRESS_RESOLVER, intern); } public static InstanceInfo.Builder newBuilder(VipAddressResolver vipAddressResolver) { return new InstanceInfo.Builder(new InstanceInfo(), vipAddressResolver, (Function)null); } public InstanceInfo.Builder setInstanceId(String instanceId) { this.result.instanceId = instanceId; return this; } public InstanceInfo.Builder setAppName(String appName) { this.result.appName = (String)this.intern.apply(appName.toUpperCase(Locale.ROOT)); return this; } public InstanceInfo.Builder setAppNameForDeser(String appName) { this.result.appName = appName; return this; } public InstanceInfo.Builder setAppGroupName(String appGroupName) { if (appGroupName != null) { this.result.appGroupName = (String)this.intern.apply(appGroupName.toUpperCase(Locale.ROOT)); } else { this.result.appGroupName = null; } return this; } public InstanceInfo.Builder setAppGroupNameForDeser(String appGroupName) { this.result.appGroupName = appGroupName; return this; } public InstanceInfo.Builder setHostName(String hostName) { if (hostName != null && !hostName.isEmpty()) { String existingHostName = this.result.hostName; this.result.hostName = hostName; if (existingHostName != null && !hostName.equals(existingHostName)) { this.refreshStatusPageUrl().refreshHealthCheckUrl().refreshVIPAddress().refreshSecureVIPAddress(); } return this; } else { InstanceInfo.logger.warn("Passed in hostname is blank, not setting it"); return this; } } public InstanceInfo.Builder setStatus(InstanceInfo.InstanceStatus status) { this.result.status = status; return this; } public InstanceInfo.Builder setOverriddenStatus(InstanceInfo.InstanceStatus status) { this.result.overriddenStatus = status; return this; } public InstanceInfo.Builder setIPAddr(String ip) { this.result.ipAddr = ip; return this; } /** @deprecated */ @Deprecated public InstanceInfo.Builder setSID(String sid) { this.result.sid = sid; return this; } public InstanceInfo.Builder setPort(int port) { this.result.port = port; return this; } public InstanceInfo.Builder setSecurePort(int port) { this.result.securePort = port; return this; } public InstanceInfo.Builder enablePort(InstanceInfo.PortType type, boolean isEnabled) { if (type == InstanceInfo.PortType.SECURE) { this.result.isSecurePortEnabled = isEnabled; } else { this.result.isUnsecurePortEnabled = isEnabled; } return this; } /** @deprecated */ @Deprecated public InstanceInfo.Builder setCountryId(int id) { this.result.countryId = id; return this; } public InstanceInfo.Builder setHomePageUrl(String relativeUrl, String explicitUrl) { String hostNameInterpolationExpression = "${" + this.namespace + "hostname}"; if (explicitUrl != null) { this.result.homePageUrl = explicitUrl.replace(hostNameInterpolationExpression, this.result.hostName); } else if (relativeUrl != null) { this.result.homePageUrl = "http://" + this.result.hostName + ":" + this.result.port + relativeUrl; } return this; } public InstanceInfo.Builder setHomePageUrlForDeser(String homePageUrl) { this.result.homePageUrl = homePageUrl; return this; } public InstanceInfo.Builder setStatusPageUrl(String relativeUrl, String explicitUrl) { String hostNameInterpolationExpression = "${" + this.namespace + "hostname}"; this.result.statusPageRelativeUrl = relativeUrl; this.result.statusPageExplicitUrl = explicitUrl; if (explicitUrl != null) { this.result.statusPageUrl = explicitUrl.replace(hostNameInterpolationExpression, this.result.hostName); } else if (relativeUrl != null) { this.result.statusPageUrl = "http://" + this.result.hostName + ":" + this.result.port + relativeUrl; } return this; } public InstanceInfo.Builder setStatusPageUrlForDeser(String statusPageUrl) { this.result.statusPageUrl = statusPageUrl; return this; } public InstanceInfo.Builder setHealthCheckUrls(String relativeUrl, String explicitUrl, String secureExplicitUrl) { String hostNameInterpolationExpression = "${" + this.namespace + "hostname}"; this.result.healthCheckRelativeUrl = relativeUrl; this.result.healthCheckExplicitUrl = explicitUrl; this.result.healthCheckSecureExplicitUrl = secureExplicitUrl; if (explicitUrl != null) { this.result.healthCheckUrl = explicitUrl.replace(hostNameInterpolationExpression, this.result.hostName); } else if (this.result.isUnsecurePortEnabled) { this.result.healthCheckUrl = "http://" + this.result.hostName + ":" + this.result.port + relativeUrl; } if (secureExplicitUrl != null) { this.result.secureHealthCheckUrl = secureExplicitUrl.replace(hostNameInterpolationExpression, this.result.hostName); } else if (this.result.isSecurePortEnabled) { this.result.secureHealthCheckUrl = "https://" + this.result.hostName + ":" + this.result.securePort + relativeUrl; } return this; } public InstanceInfo.Builder setHealthCheckUrlsForDeser(String healthCheckUrl, String secureHealthCheckUrl) { if (healthCheckUrl != null) { this.result.healthCheckUrl = healthCheckUrl; } if (secureHealthCheckUrl != null) { this.result.secureHealthCheckUrl = secureHealthCheckUrl; } return this; } public InstanceInfo.Builder setVIPAddress(String vipAddress) { this.result.vipAddressUnresolved = (String)this.intern.apply(vipAddress); this.result.vipAddress = (String)this.intern.apply(this.vipAddressResolver.resolveDeploymentContextBasedVipAddresses(vipAddress)); return this; } public InstanceInfo.Builder setVIPAddressDeser(String vipAddress) { this.result.vipAddress = (String)this.intern.apply(vipAddress); return this; } public InstanceInfo.Builder setSecureVIPAddress(String secureVIPAddress) { this.result.secureVipAddressUnresolved = (String)this.intern.apply(secureVIPAddress); this.result.secureVipAddress = (String)this.intern.apply(this.vipAddressResolver.resolveDeploymentContextBasedVipAddresses(secureVIPAddress)); return this; } public InstanceInfo.Builder setSecureVIPAddressDeser(String secureVIPAddress) { this.result.secureVipAddress = (String)this.intern.apply(secureVIPAddress); return this; } public InstanceInfo.Builder setDataCenterInfo(DataCenterInfo datacenter) { this.result.dataCenterInfo = datacenter; return this; } public InstanceInfo.Builder setLeaseInfo(LeaseInfo info) { this.result.leaseInfo = info; return this; } public InstanceInfo.Builder add(String key, String val) { this.result.metadata.put(key, val); return this; } public InstanceInfo.Builder setMetadata(Map<String, String> mt) { this.result.metadata = mt; return this; } public InstanceInfo getRawInstance() { return this.result; } public InstanceInfo build() { if (!this.isInitialized()) { throw new IllegalStateException("name is required!"); } else { return this.result; } } public boolean isInitialized() { return this.result.appName != null; } public InstanceInfo.Builder setASGName(String asgName) { this.result.asgName = (String)this.intern.apply(asgName); return this; } private InstanceInfo.Builder refreshStatusPageUrl() { this.setStatusPageUrl(this.result.statusPageRelativeUrl, this.result.statusPageExplicitUrl); return this; } private InstanceInfo.Builder refreshHealthCheckUrl() { this.setHealthCheckUrls(this.result.healthCheckRelativeUrl, this.result.healthCheckExplicitUrl, this.result.healthCheckSecureExplicitUrl); return this; } private InstanceInfo.Builder refreshSecureVIPAddress() { this.setSecureVIPAddress(this.result.secureVipAddressUnresolved); return this; } private InstanceInfo.Builder refreshVIPAddress() { this.setVIPAddress(this.result.vipAddressUnresolved); return this; } public InstanceInfo.Builder setIsCoordinatingDiscoveryServer(boolean isCoordinatingDiscoveryServer) { this.result.isCoordinatingDiscoveryServer = isCoordinatingDiscoveryServer; return this; } public InstanceInfo.Builder setLastUpdatedTimestamp(long lastUpdatedTimestamp) { this.result.lastUpdatedTimestamp = lastUpdatedTimestamp; return this; } public InstanceInfo.Builder setLastDirtyTimestamp(long lastDirtyTimestamp) { this.result.lastDirtyTimestamp = lastDirtyTimestamp; return this; } public InstanceInfo.Builder setActionType(InstanceInfo.ActionType actionType) { this.result.actionType = actionType; return this; } public InstanceInfo.Builder setNamespace(String namespace) { this.namespace = namespace.endsWith(".") ? namespace : namespace + "."; return this; } private static final class LazyHolder { private static final VipAddressResolver DEFAULT_VIP_ADDRESS_RESOLVER = new Archaius1VipAddressResolver(); private LazyHolder() { } } } public static enum PortType { SECURE, UNSECURE; private PortType() { } } public static enum InstanceStatus { UP, DOWN, STARTING, OUT_OF_SERVICE, UNKNOWN; private InstanceStatus() { } public static InstanceInfo.InstanceStatus toEnum(String s) { if (s != null) { try { return valueOf(s.toUpperCase()); } catch (IllegalArgumentException var2) { InstanceInfo.logger.debug("illegal argument supplied to InstanceStatus.valueOf: {}, defaulting to {}", s, UNKNOWN); } } return UNKNOWN; } } public static class PortWrapper { private final boolean enabled; private final int port; @JsonCreator public PortWrapper(@JsonProperty("@enabled") boolean enabled, @JsonProperty("$") int port) { this.enabled = enabled; this.port = port; } public boolean isEnabled() { return this.enabled; } public int getPort() { return this.port; } } }
InstanceInfo封装了将被发送到Eureka Server进行注册的服务实例元数据
它在Eureka Server列表中代表一个服务实例,其他服务可以通过instanceInfo了解到该服务的实例相关信息,包括地址等,从而发起请求
查看EurekaInstanceConfig.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.netflix.appinfo; import com.google.inject.ImplementedBy; import java.util.Map; @ImplementedBy(CloudInstanceConfig.class) public interface EurekaInstanceConfig { String getInstanceId(); String getAppname(); String getAppGroupName(); boolean isInstanceEnabledOnit(); int getNonSecurePort(); int getSecurePort(); boolean isNonSecurePortEnabled(); boolean getSecurePortEnabled(); int getLeaseRenewalIntervalInSeconds(); int getLeaseExpirationDurationInSeconds(); String getVirtualHostName(); String getSecureVirtualHostName(); String getASGName(); String getHostName(boolean var1); Map<String, String> getMetadataMap(); DataCenterInfo getDataCenterInfo(); String getIpAddress(); String getStatusPageUrlPath(); String getStatusPageUrl(); String getHomePageUrlPath(); String getHomePageUrl(); String getHealthCheckUrlPath(); String getHealthCheckUrl(); String getSecureHealthCheckUrl(); String[] getDefaultAddressResolutionOrder(); String getNamespace(); }
这是个接口
CloudEurekaInstanceConfig继承了该类
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.cloud.netflix.eureka; import com.netflix.appinfo.EurekaInstanceConfig; import com.netflix.appinfo.InstanceInfo.InstanceStatus; public interface CloudEurekaInstanceConfig extends EurekaInstanceConfig { void setNonSecurePort(int port); void setSecurePort(int securePort); InstanceStatus getInitialStatus(); }
EurekaInstanceConfigBean实现了CloudEurekaInstanceConfig接口
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.cloud.netflix.eureka; import com.netflix.appinfo.DataCenterInfo; import com.netflix.appinfo.MyDataCenterInfo; import com.netflix.appinfo.DataCenterInfo.Name; import com.netflix.appinfo.InstanceInfo.InstanceStatus; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Objects; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.commons.util.InetUtils; import org.springframework.cloud.commons.util.InetUtils.HostInfo; import org.springframework.context.EnvironmentAware; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; @ConfigurationProperties("eureka.instance") public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, EnvironmentAware { private static final String UNKNOWN = "unknown"; private HostInfo hostInfo; private InetUtils inetUtils; private String actuatorPrefix = "/actuator"; private String appname = "unknown"; private String appGroupName; private boolean instanceEnabledOnit; private int nonSecurePort = 80; private int securePort = 443; private boolean nonSecurePortEnabled = true; private boolean securePortEnabled; private int leaseRenewalIntervalInSeconds = 30; private int leaseExpirationDurationInSeconds = 90; private String virtualHostName = "unknown"; private String instanceId; private String secureVirtualHostName = "unknown"; private String aSGName; private Map<String, String> metadataMap = new HashMap(); private DataCenterInfo dataCenterInfo; private String ipAddress; private String statusPageUrlPath; private String statusPageUrl; private String homePageUrlPath; private String homePageUrl; private String healthCheckUrlPath; private String healthCheckUrl; private String secureHealthCheckUrl; private String namespace; private String hostname; private boolean preferIpAddress; private InstanceStatus initialStatus; private String[] defaultAddressResolutionOrder; private Environment environment; public String getHostname() { return this.getHostName(false); } private EurekaInstanceConfigBean() { this.dataCenterInfo = new MyDataCenterInfo(Name.MyOwn); this.statusPageUrlPath = this.actuatorPrefix + "/info"; this.homePageUrlPath = "/"; this.healthCheckUrlPath = this.actuatorPrefix + "/health"; this.namespace = "eureka"; this.preferIpAddress = false; this.initialStatus = InstanceStatus.UP; this.defaultAddressResolutionOrder = new String[0]; } public EurekaInstanceConfigBean(InetUtils inetUtils) { this.dataCenterInfo = new MyDataCenterInfo(Name.MyOwn); this.statusPageUrlPath = this.actuatorPrefix + "/info"; this.homePageUrlPath = "/"; this.healthCheckUrlPath = this.actuatorPrefix + "/health"; this.namespace = "eureka"; this.preferIpAddress = false; this.initialStatus = InstanceStatus.UP; this.defaultAddressResolutionOrder = new String[0]; this.inetUtils = inetUtils; this.hostInfo = this.inetUtils.findFirstNonLoopbackHostInfo(); this.ipAddress = this.hostInfo.getIpAddress(); this.hostname = this.hostInfo.getHostname(); } public String getInstanceId() { return this.instanceId == null && this.metadataMap != null ? (String)this.metadataMap.get("instanceId") : this.instanceId; } public boolean getSecurePortEnabled() { return this.securePortEnabled; } public void setHostname(String hostname) { this.hostname = hostname; this.hostInfo.override = true; } public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; this.hostInfo.override = true; } public String getHostName(boolean refresh) { if (refresh && !this.hostInfo.override) { this.ipAddress = this.hostInfo.getIpAddress(); this.hostname = this.hostInfo.getHostname(); } return this.preferIpAddress ? this.ipAddress : this.hostname; } public void setEnvironment(Environment environment) { this.environment = environment; String springAppName = this.environment.getProperty("spring.application.name", ""); if (StringUtils.hasText(springAppName)) { this.setAppname(springAppName); this.setVirtualHostName(springAppName); this.setSecureVirtualHostName(springAppName); } } private HostInfo getHostInfo() { return this.hostInfo; } private void setHostInfo(HostInfo hostInfo) { this.hostInfo = hostInfo; } private InetUtils getInetUtils() { return this.inetUtils; } private void setInetUtils(InetUtils inetUtils) { this.inetUtils = inetUtils; } public String getAppname() { return this.appname; } public void setAppname(String appname) { this.appname = appname; } public String getAppGroupName() { return this.appGroupName; } public void setAppGroupName(String appGroupName) { this.appGroupName = appGroupName; } public boolean isInstanceEnabledOnit() { return this.instanceEnabledOnit; } public void setInstanceEnabledOnit(boolean instanceEnabledOnit) { this.instanceEnabledOnit = instanceEnabledOnit; } public int getNonSecurePort() { return this.nonSecurePort; } public void setNonSecurePort(int nonSecurePort) { this.nonSecurePort = nonSecurePort; } public int getSecurePort() { return this.securePort; } public void setSecurePort(int securePort) { this.securePort = securePort; } public boolean isNonSecurePortEnabled() { return this.nonSecurePortEnabled; } public void setNonSecurePortEnabled(boolean nonSecurePortEnabled) { this.nonSecurePortEnabled = nonSecurePortEnabled; } public boolean isSecurePortEnabled() { return this.securePortEnabled; } public void setSecurePortEnabled(boolean securePortEnabled) { this.securePortEnabled = securePortEnabled; } public int getLeaseRenewalIntervalInSeconds() { return this.leaseRenewalIntervalInSeconds; } public void setLeaseRenewalIntervalInSeconds(int leaseRenewalIntervalInSeconds) { this.leaseRenewalIntervalInSeconds = leaseRenewalIntervalInSeconds; } public int getLeaseExpirationDurationInSeconds() { return this.leaseExpirationDurationInSeconds; } public void setLeaseExpirationDurationInSeconds(int leaseExpirationDurationInSeconds) { this.leaseExpirationDurationInSeconds = leaseExpirationDurationInSeconds; } public String getVirtualHostName() { return this.virtualHostName; } public void setVirtualHostName(String virtualHostName) { this.virtualHostName = virtualHostName; } public void setInstanceId(String instanceId) { this.instanceId = instanceId; } public String getSecureVirtualHostName() { return this.secureVirtualHostName; } public void setSecureVirtualHostName(String secureVirtualHostName) { this.secureVirtualHostName = secureVirtualHostName; } public String getASGName() { return this.aSGName; } public void setASGName(String aSGName) { this.aSGName = aSGName; } public Map<String, String> getMetadataMap() { return this.metadataMap; } public void setMetadataMap(Map<String, String> metadataMap) { this.metadataMap = metadataMap; } public DataCenterInfo getDataCenterInfo() { return this.dataCenterInfo; } public void setDataCenterInfo(DataCenterInfo dataCenterInfo) { this.dataCenterInfo = dataCenterInfo; } public String getIpAddress() { return this.ipAddress; } public String getStatusPageUrlPath() { return this.statusPageUrlPath; } public void setStatusPageUrlPath(String statusPageUrlPath) { this.statusPageUrlPath = statusPageUrlPath; } public String getStatusPageUrl() { return this.statusPageUrl; } public void setStatusPageUrl(String statusPageUrl) { this.statusPageUrl = statusPageUrl; } public String getHomePageUrlPath() { return this.homePageUrlPath; } public void setHomePageUrlPath(String homePageUrlPath) { this.homePageUrlPath = homePageUrlPath; } public String getHomePageUrl() { return this.homePageUrl; } public void setHomePageUrl(String homePageUrl) { this.homePageUrl = homePageUrl; } public String getHealthCheckUrlPath() { return this.healthCheckUrlPath; } public void setHealthCheckUrlPath(String healthCheckUrlPath) { this.healthCheckUrlPath = healthCheckUrlPath; } public String getHealthCheckUrl() { return this.healthCheckUrl; } public void setHealthCheckUrl(String healthCheckUrl) { this.healthCheckUrl = healthCheckUrl; } public String getSecureHealthCheckUrl() { return this.secureHealthCheckUrl; } public void setSecureHealthCheckUrl(String secureHealthCheckUrl) { this.secureHealthCheckUrl = secureHealthCheckUrl; } public String getNamespace() { return this.namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public boolean isPreferIpAddress() { return this.preferIpAddress; } public void setPreferIpAddress(boolean preferIpAddress) { this.preferIpAddress = preferIpAddress; } public InstanceStatus getInitialStatus() { return this.initialStatus; } public void setInitialStatus(InstanceStatus initialStatus) { this.initialStatus = initialStatus; } public String[] getDefaultAddressResolutionOrder() { return this.defaultAddressResolutionOrder; } public void setDefaultAddressResolutionOrder(String[] defaultAddressResolutionOrder) { this.defaultAddressResolutionOrder = defaultAddressResolutionOrder; } public Environment getEnvironment() { return this.environment; } public boolean equals(Object o) { if (this == o) { return true; } else if (o != null && this.getClass() == o.getClass()) { EurekaInstanceConfigBean that = (EurekaInstanceConfigBean)o; return Objects.equals(this.hostInfo, that.hostInfo) && Objects.equals(this.inetUtils, that.inetUtils) && Objects.equals(this.appname, that.appname) && Objects.equals(this.appGroupName, that.appGroupName) && this.instanceEnabledOnit == that.instanceEnabledOnit && this.nonSecurePort == that.nonSecurePort && this.securePort == that.securePort && this.nonSecurePortEnabled == that.nonSecurePortEnabled && this.securePortEnabled == that.securePortEnabled && this.leaseRenewalIntervalInSeconds == that.leaseRenewalIntervalInSeconds && this.leaseExpirationDurationInSeconds == that.leaseExpirationDurationInSeconds && Objects.equals(this.virtualHostName, that.virtualHostName) && Objects.equals(this.instanceId, that.instanceId) && Objects.equals(this.secureVirtualHostName, that.secureVirtualHostName) && Objects.equals(this.aSGName, that.aSGName) && Objects.equals(this.metadataMap, that.metadataMap) && Objects.equals(this.dataCenterInfo, that.dataCenterInfo) && Objects.equals(this.ipAddress, that.ipAddress) && Objects.equals(this.statusPageUrlPath, that.statusPageUrlPath) && Objects.equals(this.statusPageUrl, that.statusPageUrl) && Objects.equals(this.homePageUrlPath, that.homePageUrlPath) && Objects.equals(this.homePageUrl, that.homePageUrl) && Objects.equals(this.healthCheckUrlPath, that.healthCheckUrlPath) && Objects.equals(this.healthCheckUrl, that.healthCheckUrl) && Objects.equals(this.secureHealthCheckUrl, that.secureHealthCheckUrl) && Objects.equals(this.namespace, that.namespace) && Objects.equals(this.hostname, that.hostname) && this.preferIpAddress == that.preferIpAddress && Objects.equals(this.initialStatus, that.initialStatus) && Arrays.equals(this.defaultAddressResolutionOrder, that.defaultAddressResolutionOrder) && Objects.equals(this.environment, that.environment); } else { return false; } } public int hashCode() { return Objects.hash(new Object[]{this.hostInfo, this.inetUtils, this.appname, this.appGroupName, this.instanceEnabledOnit, this.nonSecurePort, this.securePort, this.nonSecurePortEnabled, this.securePortEnabled, this.leaseRenewalIntervalInSeconds, this.leaseExpirationDurationInSeconds, this.virtualHostName, this.instanceId, this.secureVirtualHostName, this.aSGName, this.metadataMap, this.dataCenterInfo, this.ipAddress, this.statusPageUrlPath, this.statusPageUrl, this.homePageUrlPath, this.homePageUrl, this.healthCheckUrlPath, this.healthCheckUrl, this.secureHealthCheckUrl, this.namespace, this.hostname, this.preferIpAddress, this.initialStatus, this.defaultAddressResolutionOrder, this.environment}); } public String toString() { return "EurekaInstanceConfigBean{" + "hostInfo=" + this.hostInfo + ", " + "inetUtils=" + this.inetUtils + ", " + "appname='" + this.appname + "', " + "appGroupName='" + this.appGroupName + "', " + "instanceEnabledOnit=" + this.instanceEnabledOnit + ", " + "nonSecurePort=" + this.nonSecurePort + ", " + "securePort=" + this.securePort + ", " + "nonSecurePortEnabled=" + this.nonSecurePortEnabled + ", " + "securePortEnabled=" + this.securePortEnabled + ", " + "leaseRenewalIntervalInSeconds=" + this.leaseRenewalIntervalInSeconds + ", " + "leaseExpirationDurationInSeconds=" + this.leaseExpirationDurationInSeconds + ", " + "virtualHostName='" + this.virtualHostName + "', " + "instanceId='" + this.instanceId + "', " + "secureVirtualHostName='" + this.secureVirtualHostName + "', " + "aSGName='" + this.aSGName + "', " + "metadataMap=" + this.metadataMap + ", " + "dataCenterInfo=" + this.dataCenterInfo + ", " + "ipAddress='" + this.ipAddress + "', " + "statusPageUrlPath='" + this.statusPageUrlPath + "', " + "statusPageUrl='" + this.statusPageUrl + "', " + "homePageUrlPath='" + this.homePageUrlPath + "', " + "homePageUrl='" + this.homePageUrl + "', " + "healthCheckUrlPath='" + this.healthCheckUrlPath + "', " + "healthCheckUrl='" + this.healthCheckUrl + "', " + "secureHealthCheckUrl='" + this.secureHealthCheckUrl + "', " + "namespace='" + this.namespace + "', " + "hostname='" + this.hostname + "', " + "preferIpAddress=" + this.preferIpAddress + ", " + "initialStatus=" + this.initialStatus + ", " + "defaultAddressResolutionOrder=" + Arrays.toString(this.defaultAddressResolutionOrder) + ", " + "environment=" + this.environment + ", " + "}"; } }
找到其实现类CloudInstanceConfig.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.netflix.appinfo; import com.google.inject.ProvidedBy; import com.netflix.appinfo.AmazonInfo.MetaDataKey; import com.netflix.appinfo.RefreshableAmazonInfoProvider.FallbackAddressProvider; import com.netflix.appinfo.providers.CloudInstanceConfigProvider; import javax.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton @ProvidedBy(CloudInstanceConfigProvider.class) public class CloudInstanceConfig extends PropertiesInstanceConfig implements RefreshableInstanceConfig { private static final Logger logger = LoggerFactory.getLogger(CloudInstanceConfig.class); private static final String[] DEFAULT_AWS_ADDRESS_RESOLUTION_ORDER; private final RefreshableAmazonInfoProvider amazonInfoHolder; public CloudInstanceConfig() { this("eureka"); } public CloudInstanceConfig(String namespace) { this(namespace, new Archaius1AmazonInfoConfig(namespace), (AmazonInfo)null, true); } CloudInstanceConfig(AmazonInfo info) { this("eureka", new Archaius1AmazonInfoConfig("eureka"), info, false); } CloudInstanceConfig(String namespace, RefreshableAmazonInfoProvider refreshableAmazonInfoProvider) { super(namespace); this.amazonInfoHolder = refreshableAmazonInfoProvider; } CloudInstanceConfig(String namespace, AmazonInfoConfig amazonInfoConfig, AmazonInfo initialInfo, boolean eagerInit) { super(namespace); if (eagerInit) { FallbackAddressProvider fallbackAddressProvider = new FallbackAddressProvider() { public String getFallbackIp() { return CloudInstanceConfig.super.getIpAddress(); } public String getFallbackHostname() { return CloudInstanceConfig.super.getHostName(false); } }; this.amazonInfoHolder = new RefreshableAmazonInfoProvider(amazonInfoConfig, fallbackAddressProvider); } else { this.amazonInfoHolder = new RefreshableAmazonInfoProvider(initialInfo, amazonInfoConfig); } } /** @deprecated */ @Deprecated public String resolveDefaultAddress() { return this.resolveDefaultAddress(true); } public String resolveDefaultAddress(boolean refresh) { String result = this.getHostName(refresh); String[] var3 = this.getDefaultAddressResolutionOrder(); int var4 = var3.length; for(int var5 = 0; var5 < var4; ++var5) { String name = var3[var5]; try { MetaDataKey key = MetaDataKey.valueOf(name); String address = this.amazonInfoHolder.get().get(key); if (address != null && !address.isEmpty()) { result = address; break; } } catch (Exception var9) { logger.error("failed to resolve default address for key {}, skipping", name, var9); } } return result; } public String getHostName(boolean refresh) { if (refresh) { this.amazonInfoHolder.refresh(); } return this.amazonInfoHolder.get().get(MetaDataKey.publicHostname); } public String getIpAddress() { String ipAddr = this.amazonInfoHolder.get().get(MetaDataKey.localIpv4); return ipAddr == null ? super.getIpAddress() : ipAddr; } public DataCenterInfo getDataCenterInfo() { return this.amazonInfoHolder.get(); } public String[] getDefaultAddressResolutionOrder() { String[] order = super.getDefaultAddressResolutionOrder(); return order.length == 0 ? DEFAULT_AWS_ADDRESS_RESOLUTION_ORDER : order; } /** @deprecated */ @Deprecated public synchronized void refreshAmazonInfo() { this.amazonInfoHolder.refresh(); } /** @deprecated */ @Deprecated static boolean shouldUpdate(AmazonInfo newInfo, AmazonInfo oldInfo) { return RefreshableAmazonInfoProvider.shouldUpdate(newInfo, oldInfo); } static { DEFAULT_AWS_ADDRESS_RESOLUTION_ORDER = new String[]{MetaDataKey.publicHostname.name(), MetaDataKey.localIpv4.name()}; } }
此类封装了EurekaClient自身服务实例的配置信息,主要用于构建InstanceInfo
看到此类有一段代码
- @ConfigurationProperties("eureka.instance"), 在配置文件中用eureka.instance.属性配置
- EurekaInstanceConfigBean提供了默认值
在ApplicationInfoManager中有一个方法
public void initComponent(EurekaInstanceConfig config) { try { this.config = config; this.instanceInfo = (new EurekaConfigBasedInstanceInfoProvider(config)).get(); } catch (Throwable var3) { throw new RuntimeException("Failed to initialize ApplicationInfoManager", var3); } }
查看EurekaConfigBasedInstanceInfoProvider.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.netflix.appinfo.providers; import com.google.inject.Inject; import com.netflix.appinfo.DataCenterInfo; import com.netflix.appinfo.EurekaInstanceConfig; import com.netflix.appinfo.InstanceInfo; import com.netflix.appinfo.RefreshableInstanceConfig; import com.netflix.appinfo.UniqueIdentifier; import com.netflix.appinfo.InstanceInfo.InstanceStatus; import com.netflix.appinfo.InstanceInfo.PortType; import com.netflix.appinfo.LeaseInfo.Builder; import java.util.Iterator; import java.util.Map.Entry; import javax.inject.Provider; import javax.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton public class EurekaConfigBasedInstanceInfoProvider implements Provider<InstanceInfo> { private static final Logger LOG = LoggerFactory.getLogger(EurekaConfigBasedInstanceInfoProvider.class); private final EurekaInstanceConfig config; private InstanceInfo instanceInfo; @Inject( optional = true ) private VipAddressResolver vipAddressResolver = null; @Inject public EurekaConfigBasedInstanceInfoProvider(EurekaInstanceConfig config) { this.config = config; } public synchronized InstanceInfo get() { if (this.instanceInfo == null) { Builder leaseInfoBuilder = Builder.newBuilder().setRenewalIntervalInSecs(this.config.getLeaseRenewalIntervalInSeconds()).setDurationInSecs(this.config.getLeaseExpirationDurationInSeconds()); if (this.vipAddressResolver == null) { this.vipAddressResolver = new Archaius1VipAddressResolver(); } com.netflix.appinfo.InstanceInfo.Builder builder = com.netflix.appinfo.InstanceInfo.Builder.newBuilder(this.vipAddressResolver); String instanceId = this.config.getInstanceId(); if (instanceId == null || instanceId.isEmpty()) { DataCenterInfo dataCenterInfo = this.config.getDataCenterInfo(); if (dataCenterInfo instanceof UniqueIdentifier) { instanceId = ((UniqueIdentifier)dataCenterInfo).getId(); } else { instanceId = this.config.getHostName(false); } } String defaultAddress; if (this.config instanceof RefreshableInstanceConfig) { defaultAddress = ((RefreshableInstanceConfig)this.config).resolveDefaultAddress(false); } else { defaultAddress = this.config.getHostName(false); } if (defaultAddress == null || defaultAddress.isEmpty()) { defaultAddress = this.config.getIpAddress(); } builder.setNamespace(this.config.getNamespace()).setInstanceId(instanceId).setAppName(this.config.getAppname()).setAppGroupName(this.config.getAppGroupName()).setDataCenterInfo(this.config.getDataCenterInfo()).setIPAddr(this.config.getIpAddress()).setHostName(defaultAddress).setPort(this.config.getNonSecurePort()).enablePort(PortType.UNSECURE, this.config.isNonSecurePortEnabled()).setSecurePort(this.config.getSecurePort()).enablePort(PortType.SECURE, this.config.getSecurePortEnabled()).setVIPAddress(this.config.getVirtualHostName()).setSecureVIPAddress(this.config.getSecureVirtualHostName()).setHomePageUrl(this.config.getHomePageUrlPath(), this.config.getHomePageUrl()).setStatusPageUrl(this.config.getStatusPageUrlPath(), this.config.getStatusPageUrl()).setASGName(this.config.getASGName()).setHealthCheckUrls(this.config.getHealthCheckUrlPath(), this.config.getHealthCheckUrl(), this.config.getSecureHealthCheckUrl()); if (!this.config.isInstanceEnabledOnit()) { InstanceStatus initialStatus = InstanceStatus.STARTING; LOG.info("Setting initial instance status as: {}", initialStatus); builder.setStatus(initialStatus); } else { LOG.info("Setting initial instance status as: {}. This may be too early for the instance to advertise itself as available. You would instead want to control this via a healthcheck handler.", InstanceStatus.UP); } Iterator var10 = this.config.getMetadataMap().entrySet().iterator(); while(var10.hasNext()) { Entry<String, String> mapEntry = (Entry)var10.next(); String key = (String)mapEntry.getKey(); String value = (String)mapEntry.getValue(); if (value != null && !value.isEmpty()) { builder.add(key, value); } } this.instanceInfo = builder.build(); this.instanceInfo.setLeaseInfo(leaseInfoBuilder.build()); } return this.instanceInfo; } }
发现正是通过EurekaInstanceConfig构造instanceInfo
顶级接口DiscoveryClient
eurekaClient的父类LookupService.class
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package com.netflix.discovery.shared; import com.netflix.appinfo.InstanceInfo; import java.util.List; public interface LookupService<T> { Application getApplication(String var1); Applications getApplications(); List<InstanceInfo> getInstancesById(String var1); InstanceInfo getNextServerFromEureka(String var1, boolean var2); }
LookupService作用:发现活跃的服务实例
- 根据服务实例注册的appName来获取封装有相同appName的服务实例信息容器,Application getApplication(String appName)
- 获取所有的服务实例信息,Applications getApplications()
- 根据实例id,获取服务实例信息,List getInstancesById(String id)
上面提到一个Application,它持有服务实例信息列表,它是同一个服务的集群信息
Applications是注册表中,所有服务实例信息的集合
instanceInfo代表一个服务实例的信息
为了保证原子性,比如对某个instanceInfo的操作,使用了大量同步的代码
比如下面代码:
public void addInstance(InstanceInfo i) {
instancesMap.put(i.getId(), i);
synchronized (instances) {
instances.remove(i);
instances.add(i);
isDirty = true;
}
}
睁开眼,书在面前 闭上眼,书在心里