目录
概况
@EnableEurekaClient
EnableDiscoveryClientImportSelector类
SpringFactoriesLoader类
spring.factories
AutoServiceRegistrationConfiguration类
EurekaClientAutoConfiguration类-Eureka相关bean实例化
CloudEurekaClient类
DiscoveryClient类-初始化instance&任务执行器
register-注册
renew-续约
unregister-下线
CacheRefreshThread-刷新注册信息线程
HeartbeatThread-心跳续约线程
InstanceInfoReplicator-实例信息复制线程
EurekaDiscoveryClientConfiguration类
EurekaClientAutoConfiguration类
EurekaDiscoveryClient类-拉取注册instances
EurekaRibbonClientConfiguration类-实例化robbin client接口
源码版本:2.1.2.RELEASE
eureka-client:1.9.12
该注解主要引及EnableDiscoveryClientImportSelector类
EnableDiscoveryClientImportSelector类
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EnableDiscoveryClientImportSelector.class}) //导入EnableDiscoveryClientImportSelector类
public @interface EnableDiscoveryClient {
boolean autoRegister() default true;
}
@Order(2147483547)
public class EnableDiscoveryClientImportSelector extends SpringFactoryImportSelector {
public EnableDiscoveryClientImportSelector() {
}
//选择数据元
public String[] selectImports(AnnotationMetadata metadata) {
//1 获取注册到spring的元数据
String[] imports = super.selectImports(metadata);
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(this.getAnnotationClass().getName(), true));
boolean autoRegister = attributes.getBoolean("autoRegister");
//2 autoRegister默认为true,则注册AutoServiceRegistrationConfiguration类到Spring中
if (autoRegister) {
List importsList = new ArrayList(Arrays.asList(imports));
importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = (String[])importsList.toArray(new String[0]);
} else {
Environment env = this.getEnvironment();
if (ConfigurableEnvironment.class.isInstance(env)) {
ConfigurableEnvironment configEnv = (ConfigurableEnvironment)env;
LinkedHashMap map = new LinkedHashMap();
map.put("spring.cloud.service-registry.auto-registration.enabled", false);
MapPropertySource propertySource = new MapPropertySource("springCloudDiscoveryClient", map);
configEnv.getPropertySources().addLast(propertySource);
}
}
return imports;
}
其中1中metadata数据中:
EnableDiscoveryClientImportSelector类 selectImports(metadata)方法
public String[] selectImports(AnnotationMetadata metadata) {
if (!this.isEnabled()) {
return new String[0];
} else {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(this.annotationClass.getName(), true));
Assert.notNull(attributes, "No " + this.getSimpleName() + " attributes found. Is " + metadata.getClassName() + " annotated with @" + this.getSimpleName() + "?");
//根据annotationClass获取factories
List factories = new ArrayList(new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(this.annotationClass, this.beanClassLoader)));
if (factories.isEmpty() && !this.hasDefaultFactory()) {
throw new IllegalStateException("Annotation @" + this.getSimpleName() + " found, but there are no implementations. Did you forget to include a starter?");
} else {
if (factories.size() > 1) {
this.log.warn("More than one implementation of @" + this.getSimpleName() + " (now relying on @Conditionals to pick one): " + factories);
}
return (String[])factories.toArray(new String[factories.size()]);
}
}
}
loadSpringFactories方法
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
//springboot加载后,由于缓存已经存在,此时result不为空,故直接返回。见下图
MultiValueMap result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
// 2.获取所有 META-INF/spring.factories文件
Enumeration urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
// 3.遍历所有spring.factories文件
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry, ?> entry = (Entry)var6.next();
String factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
// 4.获取properties中key为EnableDiscoveryClient对应的value值列表
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
//缓存结果
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
META-INF/spring.factories,其中org.springframework.cloud.client.discovery.EnableDiscoveryClient对应的value值
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration
但此时,你debugger发现通过SpringFactoriesLoader类loadSpringFactories中直接返回了,而不会去读spring.factories了,所以2中些时只imports中数据为:AutoServiceRegistrationConfiguration.class。
@Configuration
@EnableConfigurationProperties({AutoServiceRegistrationProperties.class})
@ConditionalOnProperty(
value = {"spring.cloud.service-registry.auto-registration.enabled"},
matchIfMissing = true
)
public class AutoServiceRegistrationConfiguration {
public AutoServiceRegistrationConfiguration() {
}
}
这是因为
由于springboot启动时通过@SpringBootApplication已经加载上述上装载类org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration
且看该类:原来在此时已经import了EurekaClientAutoConfiguration类
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass({EurekaClientConfig.class})
@Import({DiscoveryClientOptionalArgsConfiguration.class})
@ConditionalOnBean({Marker.class})
@ConditionalOnProperty(
value = {"eureka.client.enabled"},
matchIfMissing = true
)
@ConditionalOnDiscoveryEnabled
@AutoConfigureBefore({NoopDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class})
@AutoConfigureAfter(
name = {"org.springframework.cloud.autoconfigure.RefreshAutoConfiguration", "org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration", "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"}
)
public class EurekaClientAutoConfiguration {
...
@Bean
@ConditionalOnMissingBean(
value = {EurekaInstanceConfig.class},
search = SearchStrategy.CURRENT
)
public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) {
String hostname = this.getProperty("eureka.instance.hostname");
boolean preferIpAddress = Boolean.parseBoolean(this.getProperty("eureka.instance.prefer-ip-address"));
String ipAddress = this.getProperty("eureka.instance.ip-address");
boolean isSecurePortEnabled = Boolean.parseBoolean(this.getProperty("eureka.instance.secure-port-enabled"));
String serverContextPath = this.env.getProperty("server.servlet.context-path", "/");
int serverPort = Integer.valueOf(this.env.getProperty("server.port", this.env.getProperty("port", "8080")));
Integer managementPort = (Integer)this.env.getProperty("management.server.port", Integer.class);
String managementContextPath = this.env.getProperty("management.server.servlet.context-path");
Integer jmxPort = (Integer)this.env.getProperty("com.sun.management.jmxremote.port", Integer.class);
EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
instance.setNonSecurePort(serverPort);
instance.setInstanceId(IdUtils.getDefaultInstanceId(this.env));
instance.setPreferIpAddress(preferIpAddress);
instance.setSecurePortEnabled(isSecurePortEnabled);
if (StringUtils.hasText(ipAddress)) {
instance.setIpAddress(ipAddress);
}
if (isSecurePortEnabled) {
instance.setSecurePort(serverPort);
}
if (StringUtils.hasText(hostname)) {
instance.setHostname(hostname);
}
String statusPageUrlPath = this.getProperty("eureka.instance.status-page-url-path");
String healthCheckUrlPath = this.getProperty("eureka.instance.health-check-url-path");
if (StringUtils.hasText(statusPageUrlPath)) {
instance.setStatusPageUrlPath(statusPageUrlPath);
}
if (StringUtils.hasText(healthCheckUrlPath)) {
instance.setHealthCheckUrlPath(healthCheckUrlPath);
}
ManagementMetadata metadata = managementMetadataProvider.get(instance, serverPort, serverContextPath, managementContextPath, managementPort);
if (metadata != null) {
instance.setStatusPageUrl(metadata.getStatusPageUrl());
instance.setHealthCheckUrl(metadata.getHealthCheckUrl());
if (instance.isSecurePortEnabled()) {
instance.setSecureHealthCheckUrl(metadata.getSecureHealthCheckUrl());
}
Map metadataMap = instance.getMetadataMap();
metadataMap.computeIfAbsent("management.port", (k) -> {
return String.valueOf(metadata.getManagementPort());
});
} else if (StringUtils.hasText(managementContextPath)) {
instance.setHealthCheckUrlPath(managementContextPath + instance.getHealthCheckUrlPath());
instance.setStatusPageUrlPath(managementContextPath + instance.getStatusPageUrlPath());
}
this.setupJmxPort(instance, jmxPort);
return instance;
}
private void setupJmxPort(EurekaInstanceConfigBean instance, Integer jmxPort) {
Map metadataMap = instance.getMetadataMap();
if (metadataMap.get("jmx.port") == null && jmxPort != null) {
metadataMap.put("jmx.port", String.valueOf(jmxPort));
}
}
@Bean
public DiscoveryClient discoveryClient(EurekaClient client, EurekaClientConfig clientConfig) {
return new EurekaDiscoveryClient(client, clientConfig);
}
@Bean
public EurekaServiceRegistry eurekaServiceRegistry() {
return new EurekaServiceRegistry();
}
@Bean
@ConditionalOnBean({AutoServiceRegistrationProperties.class})
@ConditionalOnProperty(
value = {"spring.cloud.service-registry.auto-registration.enabled"},
matchIfMissing = true
)
public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry registry, EurekaRegistration registration) {
return new EurekaAutoServiceRegistration(context, registry, registration);
}
....
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ConditionalOnClass({RefreshScope.class})
@ConditionalOnBean({RefreshAutoConfiguration.class})
@ConditionalOnProperty(
value = {"eureka.client.refresh.enable"},
havingValue = "true",
matchIfMissing = true
)
@interface ConditionalOnRefreshScope {
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({EurekaClientAutoConfiguration.OnMissingRefreshScopeCondition.class})
@interface ConditionalOnMissingRefreshScope {
}
@Configuration
@EurekaClientAutoConfiguration.ConditionalOnRefreshScope
protected static class RefreshableEurekaClientConfiguration {
@Autowired
private ApplicationContext context;
@Autowired
private AbstractDiscoveryClientOptionalArgs> optionalArgs;
protected RefreshableEurekaClientConfiguration() {
}
@Bean(
destroyMethod = "shutdown"
)
@ConditionalOnMissingBean(
value = {EurekaClient.class},
search = SearchStrategy.CURRENT
)
@org.springframework.cloud.context.config.annotation.RefreshScope
@Lazy
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config, EurekaInstanceConfig instance, @Autowired(required = false) HealthCheckHandler healthCheckHandler) {
ApplicationInfoManager appManager;
if (AopUtils.isAopProxy(manager)) {
appManager = (ApplicationInfoManager)ProxyUtils.getTargetObject(manager);
} else {
appManager = manager;
}
//创建EurekaClient注册器
CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager, config, this.optionalArgs, this.context);
cloudEurekaClient.registerHealthCheck(healthCheckHandler);
return cloudEurekaClient;
}
@Bean
@ConditionalOnMissingBean(
value = {ApplicationInfoManager.class},
search = SearchStrategy.CURRENT
)
@org.springframework.cloud.context.config.annotation.RefreshScope
@Lazy
public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
InstanceInfo instanceInfo = (new InstanceInfoFactory()).create(config);
return new ApplicationInfoManager(config, instanceInfo);
}
@Bean
@org.springframework.cloud.context.config.annotation.RefreshScope
@ConditionalOnBean({AutoServiceRegistrationProperties.class})
@ConditionalOnProperty(
value = {"spring.cloud.service-registry.auto-registration.enabled"},
matchIfMissing = true
)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager, @Autowired(required = false) ObjectProvider healthCheckHandler) {
return EurekaRegistration.builder(instanceConfig).with(applicationInfoManager).with(eurekaClient).with(healthCheckHandler).build();
}
}
}
public class CloudEurekaClient extends DiscoveryClient {
...
public CloudEurekaClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, ApplicationEventPublisher publisher) {
this(applicationInfoManager, config, (AbstractDiscoveryClientOptionalArgs)null, publisher);
}
public CloudEurekaClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs> args, ApplicationEventPublisher publisher) {
//继承父类构造
super(applicationInfoManager, config, args);
this.cacheRefreshedCount = new AtomicLong(0L);
this.eurekaHttpClient = new AtomicReference();
this.applicationInfoManager = applicationInfoManager;
this.publisher = publisher;
this.eurekaTransportField = ReflectionUtils.findField(DiscoveryClient.class, "eurekaTransport");
ReflectionUtils.makeAccessible(this.eurekaTransportField);
}
}
启动三个线程
heartbeatExecutor:初始化&启动心跳执行器
cacheRefreshExecutor:初始化&启动获取缓存信息到本地执行器
InstanceInfoReplicator:实例信息复制线程
重要执行逻辑
在执行上续方法同时会通过replicateToPeers()向集群中其它节点发送数据
参数说明
eureka.client.refres.enable 实例是否刷新 默认为true
eureka.client.fetchRegistry 是否拉取注册信息 默认为true
eureka.client.registry-fetch-interval-seconds拉取注册信息时间间隔 默认30s
eureka.client.registerWithEureka 是否将实例注册到Eureka上 默认为true
eureka.instance.lease-renewal-interval-in-seconds发送心跳时间间隔 默认30s
eureka.instance.lease-expiration-duration-in-seconds心跳超时时间,超时踢出实例 默认90
@Singleton
public class DiscoveryClient implements EurekaClient {
...
public DiscoveryClient(ApplicationInfoManager applicationInfoManager, final EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, EndpointRandomizer randomizer) {
this(applicationInfoManager, config, args, new Provider() {
private volatile BackupRegistry backupRegistryInstance;
public synchronized BackupRegistry get() {
if (this.backupRegistryInstance == null) {
String backupRegistryClassName = config.getBackupRegistryImpl();
if (null != backupRegistryClassName) {
try {
this.backupRegistryInstance = (BackupRegistry)Class.forName(backupRegistryClassName).newInstance();
DiscoveryClient.logger.info("Enabled backup registry of type {}", this.backupRegistryInstance.getClass());
} catch (InstantiationException var3) {
DiscoveryClient.logger.error("Error instantiating BackupRegistry.", var3);
} catch (IllegalAccessException var4) {
DiscoveryClient.logger.error("Error instantiating BackupRegistry.", var4);
} catch (ClassNotFoundException var5) {
DiscoveryClient.logger.error("Error instantiating BackupRegistry.", var5);
}
}
if (this.backupRegistryInstance == null) {
DiscoveryClient.logger.warn("Using default backup registry implementation which does not do anything.");
this.backupRegistryInstance = new NotImplementedRegistryImpl();
}
}
return this.backupRegistryInstance;
}
}, randomizer);
}
//初始化instance
@Inject
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider backupRegistryProvider, EndpointRandomizer endpointRandomizer) {
this.RECONCILE_HASH_CODES_MISMATCH = Monitors.newCounter("DiscoveryClient_ReconcileHashCodeMismatch");
this.FETCH_REGISTRY_TIMER = Monitors.newTimer("DiscoveryClient_FetchRegistry");
this.REREGISTER_COUNTER = Monitors.newCounter("DiscoveryClient_Reregister");
this.localRegionApps = new AtomicReference();
this.fetchRegistryUpdateLock = new ReentrantLock();
this.healthCheckHandlerRef = new AtomicReference();
this.remoteRegionVsApps = new ConcurrentHashMap();
this.lastRemoteInstanceStatus = InstanceStatus.UNKNOWN;
this.eventListeners = new CopyOnWriteArraySet();
this.registrySize = 0;
this.lastSuccessfulRegistryFetchTimestamp = -1L;
this.lastSuccessfulHeartbeatTimestamp = -1L;
this.isShutdown = new AtomicBoolean(false);
if (args != null) {
this.healthCheckHandlerProvider = args.healthCheckHandlerProvider;
this.healthCheckCallbackProvider = args.healthCheckCallbackProvider;
this.eventListeners.addAll(args.getEventListeners());
this.preRegistrationHandler = args.preRegistrationHandler;
} else {
this.healthCheckCallbackProvider = null;
this.healthCheckHandlerProvider = null;
this.preRegistrationHandler = null;
}
this.applicationInfoManager = applicationInfoManager;
InstanceInfo myInfo = applicationInfoManager.getInfo();
this.clientConfig = config;
staticClientConfig = this.clientConfig;
this.transportConfig = config.getTransportConfig();
this.instanceInfo = myInfo;
if (myInfo != null) {
this.appPathIdentifier = this.instanceInfo.getAppName() + "/" + this.instanceInfo.getId();
} else {
logger.warn("Setting instanceInfo to a passed in null value");
}
this.backupRegistryProvider = backupRegistryProvider;
this.endpointRandomizer = endpointRandomizer;
this.urlRandomizer = new InstanceInfoBasedUrlRandomizer(this.instanceInfo);
this.localRegionApps.set(new Applications());
this.fetchRegistryGeneration = new AtomicLong(0L);
this.remoteRegionsToFetch = new AtomicReference(this.clientConfig.fetchRegistryForRemoteRegions());
this.remoteRegionsRef = new AtomicReference(this.remoteRegionsToFetch.get() == null ? null : ((String)this.remoteRegionsToFetch.get()).split(","));
//默认为ture
if (config.shouldFetchRegistry()) {
this.registryStalenessMonitor = new ThresholdLevelsMetric(this, "eurekaClient.registry.lastUpdateSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
} else {
this.registryStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
}
//默认为ture
if (config.shouldRegisterWithEureka()) {
this.heartbeatStalenessMonitor = new ThresholdLevelsMetric(this, "eurekaClient.registration.lastHeartbeatSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
} else {
this.heartbeatStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
}
logger.info("Initializing Eureka in region {}", this.clientConfig.getRegion());
//shouldFetchRegistry默认为ture
if (!config.shouldRegisterWithEureka() && !config.shouldFetchRegistry()) {
logger.info("Client configured to neither register nor query for data.");
this.scheduler = null;
this.heartbeatExecutor = null;
this.cacheRefreshExecutor = null;
this.eurekaTransport = null;
this.instanceRegionChecker = new InstanceRegionChecker(new PropertyBasedAzToRegionMapper(config), this.clientConfig.getRegion());
DiscoveryManager.getInstance().setDiscoveryClient(this);
DiscoveryManager.getInstance().setEurekaClientConfig(config);
this.initTimestampMs = System.currentTimeMillis();
logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}", this.initTimestampMs, this.getApplications().size());
} else {
//设置定时调度器
//线程执行任务均为daemon,当其它线程结束后,该线程自动结束
try {
this.scheduler = Executors.newScheduledThreadPool(2, (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-%d").setDaemon(true).build());
//心跳执行器
this.heartbeatExecutor = new ThreadPoolExecutor(1, this.clientConfig.getHeartbeatExecutorThreadPoolSize(), 0L, TimeUnit.SECONDS, new SynchronousQueue(), (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-HeartbeatExecutor-%d").setDaemon(true).build());
//获取缓存执行器
this.cacheRefreshExecutor = new ThreadPoolExecutor(1, this.clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0L, TimeUnit.SECONDS, new SynchronousQueue(), (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d").setDaemon(true).build());
this.eurekaTransport = new DiscoveryClient.EurekaTransport(null);
this.scheduleServerEndpointTask(this.eurekaTransport, args);
Object azToRegionMapper;
if (this.clientConfig.shouldUseDnsForFetchingServiceUrls()) {
azToRegionMapper = new DNSBasedAzToRegionMapper(this.clientConfig);
} else {
azToRegionMapper = new PropertyBasedAzToRegionMapper(this.clientConfig);
}
if (null != this.remoteRegionsToFetch.get()) {
((AzToRegionMapper)azToRegionMapper).setRegionsToFetch(((String)this.remoteRegionsToFetch.get()).split(","));
}
this.instanceRegionChecker = new InstanceRegionChecker((AzToRegionMapper)azToRegionMapper, this.clientConfig.getRegion());
} catch (Throwable var10) {
throw new RuntimeException("Failed to initialize DiscoveryClient!", var10);
}
//获取信息失败
if (this.clientConfig.shouldFetchRegistry() && !this.fetchRegistry(false)) {
//获取备份信息
this.fetchRegistryFromBackup();
}
if (this.preRegistrationHandler != null) {
this.preRegistrationHandler.beforeRegistration();
}
if (this.clientConfig.shouldRegisterWithEureka() && this.clientConfig.shouldEnforceRegistrationAtInit()) {
try {
当实例允许注册到eureka,则强制注册&初始化
if (!this.register()) {
throw new IllegalStateException("Registration error at startup. Invalid server response.");
}
} catch (Throwable var9) {
logger.error("Registration error at startup: {}", var9.getMessage());
throw new IllegalStateException(var9);
}
}
//初始化调度器
this.initScheduledTasks();
try {
Monitors.registerObject(this);
} catch (Throwable var8) {
logger.warn("Cannot register timers", var8);
}
DiscoveryManager.getInstance().setDiscoveryClient(this);
DiscoveryManager.getInstance().setEurekaClientConfig(config);
this.initTimestampMs = System.currentTimeMillis();
logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}", this.initTimestampMs, this.getApplications().size());
}
}
...
public List getInstancesById(String id) {
List instancesList = new ArrayList();
Iterator var3 = this.getApplications().getRegisteredApplications().iterator();
while(var3.hasNext()) {
Application app = (Application)var3.next();
InstanceInfo instanceInfo = app.getByInstanceId(id);
if (instanceInfo != null) {
instancesList.add(instanceInfo);
}
}
return instancesList;
}
public void registerHealthCheck(HealthCheckHandler healthCheckHandler) {
if (this.instanceInfo == null) {
logger.error("Cannot register a healthcheck handler when instance info is null!");
}
if (healthCheckHandler != null) {
this.healthCheckHandlerRef.set(healthCheckHandler);
if (this.instanceInfoReplicator != null) {
this.instanceInfoReplicator.onDemandUpdate();
}
}
}
...
public List getInstancesByVipAddress(String vipAddress, boolean secure, @Nullable String region) {
if (vipAddress == null) {
throw new IllegalArgumentException("Supplied VIP Address cannot be null");
} else {
Applications applications;
if (this.instanceRegionChecker.isLocalRegion(region)) {
applications = (Applications)this.localRegionApps.get();
} else {
applications = (Applications)this.remoteRegionVsApps.get(region);
if (null == applications) {
logger.debug("No applications are defined for region {}, so returning an empty instance list for vip address {}.", region, vipAddress);
return Collections.emptyList();
}
}
return !secure ? applications.getInstancesByVirtualHostName(vipAddress) : applications.getInstancesBySecureVirtualHostName(vipAddress);
}
}
public List getInstancesByVipAddressAndAppName(String vipAddress, String appName, boolean secure) {
List result = new ArrayList();
if (vipAddress == null && appName == null) {
throw new IllegalArgumentException("Supplied VIP Address and application name cannot both be null");
} else if (vipAddress != null && appName == null) {
return this.getInstancesByVipAddress(vipAddress, secure);
} else if (vipAddress == null && appName != null) {
Application application = this.getApplication(appName);
if (application != null) {
result = application.getInstances();
}
return (List)result;
} else {
Iterator var6 = this.getApplications().getRegisteredApplications().iterator();
label67:
while(var6.hasNext()) {
Application app = (Application)var6.next();
Iterator var8 = app.getInstances().iterator();
while(true) {
while(true) {
String instanceVipAddress;
InstanceInfo instance;
do {
if (!var8.hasNext()) {
continue label67;
}
instance = (InstanceInfo)var8.next();
if (secure) {
instanceVipAddress = instance.getSecureVipAddress();
} else {
instanceVipAddress = instance.getVIPAddress();
}
} while(instanceVipAddress == null);
String[] instanceVipAddresses = instanceVipAddress.split(",");
String[] var11 = instanceVipAddresses;
int var12 = instanceVipAddresses.length;
for(int var13 = 0; var13 < var12; ++var13) {
String vipAddressFromList = var11[var13];
if (vipAddress.equalsIgnoreCase(vipAddressFromList.trim()) && appName.equalsIgnoreCase(instance.getAppName())) {
((List)result).add(instance);
break;
}
}
}
}
}
return (List)result;
}
}
public InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure) {
List instanceInfoList = this.getInstancesByVipAddress(virtualHostname, secure);
if (instanceInfoList != null && !instanceInfoList.isEmpty()) {
Applications apps = (Applications)this.localRegionApps.get();
int index = (int)(apps.getNextIndex(virtualHostname, secure).incrementAndGet() % (long)instanceInfoList.size());
return (InstanceInfo)instanceInfoList.get(index);
} else {
throw new RuntimeException("No matches for the virtual host name :" + virtualHostname);
}
}
public Applications getApplications(String serviceUrl) {
try {
EurekaHttpResponse response = this.clientConfig.getRegistryRefreshSingleVipAddress() == null ? this.eurekaTransport.queryClient.getApplications(new String[0]) : this.eurekaTransport.queryClient.getVip(this.clientConfig.getRegistryRefreshSingleVipAddress(), new String[0]);
if (response.getStatusCode() == Status.OK.getStatusCode()) {
logger.debug("DiscoveryClient_{} - refresh status: {}", this.appPathIdentifier, response.getStatusCode());
return (Applications)response.getEntity();
}
logger.error("DiscoveryClient_{} - was unable to refresh its cache! status = {}", this.appPathIdentifier, response.getStatusCode());
} catch (Throwable var3) {
logger.error("DiscoveryClient_{} - was unable to refresh its cache! status = {}", new Object[]{this.appPathIdentifier, var3.getMessage(), var3});
}
return null;
}
//注册
boolean register() throws Throwable {
logger.info("DiscoveryClient_{}: registering service...", this.appPathIdentifier);
EurekaHttpResponse httpResponse;
try {
httpResponse = this.eurekaTransport.registrationClient.register(this.instanceInfo);
} catch (Exception var3) {
logger.warn("DiscoveryClient_{} - registration failed {}", new Object[]{this.appPathIdentifier, var3.getMessage(), var3});
throw var3;
}
if (logger.isInfoEnabled()) {
logger.info("DiscoveryClient_{} - registration status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
}
return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();
}
//续约
boolean renew() {
try {
EurekaHttpResponse httpResponse = this.eurekaTransport.registrationClient.sendHeartBeat(this.instanceInfo.getAppName(), this.instanceInfo.getId(), this.instanceInfo, (InstanceStatus)null);
logger.debug("DiscoveryClient_{} - Heartbeat status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) {
this.REREGISTER_COUNTER.increment();
logger.info("DiscoveryClient_{} - Re-registering apps/{}", this.appPathIdentifier, this.instanceInfo.getAppName());
long timestamp = this.instanceInfo.setIsDirtyWithTime();
boolean success = this.register();
if (success) {
this.instanceInfo.unsetIsDirty(timestamp);
}
return success;
} else {
return httpResponse.getStatusCode() == Status.OK.getStatusCode();
}
} catch (Throwable var5) {
logger.error("DiscoveryClient_{} - was unable to send heartbeat!", this.appPathIdentifier, var5);
return false;
}
}
/** @deprecated */
@Deprecated
public List getServiceUrlsFromConfig(String instanceZone, boolean preferSameZone) {
return EndpointUtils.getServiceUrlsFromConfig(this.clientConfig, instanceZone, preferSameZone);
}
//下线
@PreDestroy
public synchronized void shutdown() {
if (this.isShutdown.compareAndSet(false, true)) {
logger.info("Shutting down DiscoveryClient ...");
if (this.statusChangeListener != null && this.applicationInfoManager != null) {
this.applicationInfoManager.unregisterStatusChangeListener(this.statusChangeListener.getId());
}
this.cancelScheduledTasks();
if (this.applicationInfoManager != null && this.clientConfig.shouldRegisterWithEureka() && this.clientConfig.shouldUnregisterOnShutdown()) {
this.applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN);
this.unregister();
}
if (this.eurekaTransport != null) {
this.eurekaTransport.shutdown();
}
this.heartbeatStalenessMonitor.shutdown();
this.registryStalenessMonitor.shutdown();
logger.info("Completed shut down of DiscoveryClient");
}
}
//下线
void unregister() {
if (this.eurekaTransport != null && this.eurekaTransport.registrationClient != null) {
try {
logger.info("Unregistering ...");
EurekaHttpResponse httpResponse = this.eurekaTransport.registrationClient.cancel(this.instanceInfo.getAppName(), this.instanceInfo.getId());
logger.info("DiscoveryClient_{} - deregister status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
} catch (Exception var2) {
logger.error("DiscoveryClient_{} - de-registration failed{}", new Object[]{this.appPathIdentifier, var2.getMessage(), var2});
}
}
}
private boolean fetchRegistry(boolean forceFullRegistryFetch) {
Stopwatch tracer = this.FETCH_REGISTRY_TIMER.start();
label122: {
boolean var4;
try {
Applications applications = this.getApplications();
if (!this.clientConfig.shouldDisableDelta() && Strings.isNullOrEmpty(this.clientConfig.getRegistryRefreshSingleVipAddress()) && !forceFullRegistryFetch && applications != null && applications.getRegisteredApplications().size() != 0 && applications.getVersion() != -1L) {
this.getAndUpdateDelta(applications);
} else {
logger.info("Disable delta property : {}", this.clientConfig.shouldDisableDelta());
logger.info("Single vip registry refresh property : {}", this.clientConfig.getRegistryRefreshSingleVipAddress());
logger.info("Force full registry fetch : {}", forceFullRegistryFetch);
logger.info("Application is null : {}", applications == null);
logger.info("Registered Applications size is zero : {}", applications.getRegisteredApplications().size() == 0);
logger.info("Application version is -1: {}", applications.getVersion() == -1L);
this.getAndStoreFullRegistry();
}
applications.setAppsHashCode(applications.getReconcileHashCode());
this.logTotalInstances();
break label122;
} catch (Throwable var8) {
logger.error("DiscoveryClient_{} - was unable to refresh its cache! status = {}", new Object[]{this.appPathIdentifier, var8.getMessage(), var8});
var4 = false;
} finally {
if (tracer != null) {
tracer.stop();
}
}
return var4;
}
this.onCacheRefreshed();
this.updateInstanceRemoteStatus();
return true;
}
private synchronized void updateInstanceRemoteStatus() {
InstanceStatus currentRemoteInstanceStatus = null;
if (this.instanceInfo.getAppName() != null) {
Application app = this.getApplication(this.instanceInfo.getAppName());
if (app != null) {
InstanceInfo remoteInstanceInfo = app.getByInstanceId(this.instanceInfo.getId());
if (remoteInstanceInfo != null) {
currentRemoteInstanceStatus = remoteInstanceInfo.getStatus();
}
}
}
if (currentRemoteInstanceStatus == null) {
currentRemoteInstanceStatus = InstanceStatus.UNKNOWN;
}
if (this.lastRemoteInstanceStatus != currentRemoteInstanceStatus) {
this.onRemoteStatusChanged(this.lastRemoteInstanceStatus, currentRemoteInstanceStatus);
this.lastRemoteInstanceStatus = currentRemoteInstanceStatus;
}
}
public InstanceStatus getInstanceRemoteStatus() {
return this.lastRemoteInstanceStatus;
}
private String getReconcileHashCode(Applications applications) {
TreeMap instanceCountMap = new TreeMap();
if (this.isFetchingRemoteRegionRegistries()) {
Iterator var3 = this.remoteRegionVsApps.values().iterator();
while(var3.hasNext()) {
Applications remoteApp = (Applications)var3.next();
remoteApp.populateInstanceCountMap(instanceCountMap);
}
}
applications.populateInstanceCountMap(instanceCountMap);
return Applications.getReconcileHashCode(instanceCountMap);
}
private void getAndStoreFullRegistry() throws Throwable {
long currentUpdateGeneration = this.fetchRegistryGeneration.get();
logger.info("Getting all instance registry info from the eureka server");
Applications apps = null;
EurekaHttpResponse httpResponse = this.clientConfig.getRegistryRefreshSingleVipAddress() == null ? this.eurekaTransport.queryClient.getApplications((String[])this.remoteRegionsRef.get()) : this.eurekaTransport.queryClient.getVip(this.clientConfig.getRegistryRefreshSingleVipAddress(), (String[])this.remoteRegionsRef.get());
if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
apps = (Applications)httpResponse.getEntity();
}
logger.info("The response status is {}", httpResponse.getStatusCode());
if (apps == null) {
logger.error("The application is null for some reason. Not storing this information");
} else if (this.fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1L)) {
this.localRegionApps.set(this.filterAndShuffle(apps));
logger.debug("Got full registry with apps hashcode {}", apps.getAppsHashCode());
} else {
logger.warn("Not updating applications as another thread is updating it already");
}
}
private void getAndUpdateDelta(Applications applications) throws Throwable {
long currentUpdateGeneration = this.fetchRegistryGeneration.get();
Applications delta = null;
EurekaHttpResponse httpResponse = this.eurekaTransport.queryClient.getDelta((String[])this.remoteRegionsRef.get());
if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
delta = (Applications)httpResponse.getEntity();
}
if (delta == null) {
logger.warn("The server does not allow the delta revision to be applied because it is not safe. Hence got the full registry.");
this.getAndStoreFullRegistry();
} else if (this.fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1L)) {
logger.debug("Got delta update with apps hashcode {}", delta.getAppsHashCode());
String reconcileHashCode = "";
if (this.fetchRegistryUpdateLock.tryLock()) {
try {
this.updateDelta(delta);
reconcileHashCode = this.getReconcileHashCode(applications);
} finally {
this.fetchRegistryUpdateLock.unlock();
}
} else {
logger.warn("Cannot acquire update lock, aborting getAndUpdateDelta");
}
if (!reconcileHashCode.equals(delta.getAppsHashCode()) || this.clientConfig.shouldLogDeltaDiff()) {
this.reconcileAndLogDifference(delta, reconcileHashCode);
}
} else {
logger.warn("Not updating application delta as another thread is updating it already");
logger.debug("Ignoring delta update with apps hashcode {}, as another thread is updating it already", delta.getAppsHashCode());
}
}
private void logTotalInstances() {
if (logger.isDebugEnabled()) {
int totInstances = 0;
Application application;
for(Iterator var2 = this.getApplications().getRegisteredApplications().iterator(); var2.hasNext(); totInstances += application.getInstancesAsIsFromEureka().size()) {
application = (Application)var2.next();
}
logger.debug("The total number of all instances in the client now is {}", totInstances);
}
}
private void reconcileAndLogDifference(Applications delta, String reconcileHashCode) throws Throwable {
logger.debug("The Reconcile hashcodes do not match, client : {}, server : {}. Getting the full registry", reconcileHashCode, delta.getAppsHashCode());
this.RECONCILE_HASH_CODES_MISMATCH.increment();
long currentUpdateGeneration = this.fetchRegistryGeneration.get();
EurekaHttpResponse httpResponse = this.clientConfig.getRegistryRefreshSingleVipAddress() == null ? this.eurekaTransport.queryClient.getApplications((String[])this.remoteRegionsRef.get()) : this.eurekaTransport.queryClient.getVip(this.clientConfig.getRegistryRefreshSingleVipAddress(), (String[])this.remoteRegionsRef.get());
Applications serverApps = (Applications)httpResponse.getEntity();
if (serverApps == null) {
logger.warn("Cannot fetch full registry from the server; reconciliation failure");
} else {
if (this.fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1L)) {
this.localRegionApps.set(this.filterAndShuffle(serverApps));
this.getApplications().setVersion(delta.getVersion());
logger.debug("The Reconcile hashcodes after complete sync up, client : {}, server : {}.", this.getApplications().getReconcileHashCode(), delta.getAppsHashCode());
} else {
logger.warn("Not setting the applications map as another thread has advanced the update generation");
}
}
}
private void updateDelta(Applications delta) {
int deltaCount = 0;
Iterator var3 = delta.getRegisteredApplications().iterator();
while(var3.hasNext()) {
Application app = (Application)var3.next();
Iterator var5 = app.getInstances().iterator();
while(var5.hasNext()) {
InstanceInfo instance = (InstanceInfo)var5.next();
Applications applications = this.getApplications();
String instanceRegion = this.instanceRegionChecker.getInstanceRegion(instance);
if (!this.instanceRegionChecker.isLocalRegion(instanceRegion)) {
Applications remoteApps = (Applications)this.remoteRegionVsApps.get(instanceRegion);
if (null == remoteApps) {
remoteApps = new Applications();
this.remoteRegionVsApps.put(instanceRegion, remoteApps);
}
applications = remoteApps;
}
++deltaCount;
Application existingApp;
if (ActionType.ADDED.equals(instance.getActionType())) {
existingApp = applications.getRegisteredApplications(instance.getAppName());
if (existingApp == null) {
applications.addApplication(app);
}
logger.debug("Added instance {} to the existing apps in region {}", instance.getId(), instanceRegion);
applications.getRegisteredApplications(instance.getAppName()).addInstance(instance);
} else if (ActionType.MODIFIED.equals(instance.getActionType())) {
existingApp = applications.getRegisteredApplications(instance.getAppName());
if (existingApp == null) {
applications.addApplication(app);
}
logger.debug("Modified instance {} to the existing apps ", instance.getId());
applications.getRegisteredApplications(instance.getAppName()).addInstance(instance);
} else if (ActionType.DELETED.equals(instance.getActionType())) {
existingApp = applications.getRegisteredApplications(instance.getAppName());
if (existingApp != null) {
logger.debug("Deleted instance {} to the existing apps ", instance.getId());
existingApp.removeInstance(instance);
if (existingApp.getInstancesAsIsFromEureka().isEmpty()) {
applications.removeApplication(existingApp);
}
}
}
}
}
logger.debug("The total number of instances fetched by the delta processor : {}", deltaCount);
this.getApplications().setVersion(delta.getVersion());
this.getApplications().shuffleInstances(this.clientConfig.shouldFilterOnlyUpInstances());
var3 = this.remoteRegionVsApps.values().iterator();
while(var3.hasNext()) {
Applications applications = (Applications)var3.next();
applications.setVersion(delta.getVersion());
applications.shuffleInstances(this.clientConfig.shouldFilterOnlyUpInstances());
}
}
private void initScheduledTasks() {
int renewalIntervalInSecs;
int expBackOffBound;
//获取缓存信息到本地 默认30s 参数:RegistryFetchIntervalSeconds
if (this.clientConfig.shouldFetchRegistry()) {
renewalIntervalInSecs = this.clientConfig.getRegistryFetchIntervalSeconds();
expBackOffBound = this.clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
this.scheduler.schedule(new TimedSupervisorTask("cacheRefresh", this.scheduler, this.cacheRefreshExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.CacheRefreshThread()), (long)renewalIntervalInSecs, TimeUnit.SECONDS);
}
//续约 30s 参数:getRenewalIntervalInSecs
if (this.clientConfig.shouldRegisterWithEureka()) {
renewalIntervalInSecs = this.instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
expBackOffBound = this.clientConfig.getHeartbeatExecutorExponentialBackOffBound();
logger.info("Starting heartbeat executor: renew interval is: {}", renewalIntervalInSecs);
this.scheduler.schedule(new TimedSupervisorTask("heartbeat", this.scheduler, this.heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new DiscoveryClient.HeartbeatThread(null)), (long)renewalIntervalInSecs, TimeUnit.SECONDS);
this.instanceInfoReplicator = new InstanceInfoReplicator(this, this.instanceInfo, this.clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2);
this.statusChangeListener = new StatusChangeListener() {
public String getId() {
return "statusChangeListener";
}
public void notify(StatusChangeEvent statusChangeEvent) {
if (InstanceStatus.DOWN != statusChangeEvent.getStatus() && InstanceStatus.DOWN != statusChangeEvent.getPreviousStatus()) {
DiscoveryClient.logger.info("Saw local status change event {}", statusChangeEvent);
} else {
DiscoveryClient.logger.warn("Saw local status change event {}", statusChangeEvent);
}
DiscoveryClient.this.instanceInfoReplicator.onDemandUpdate();
}
};
if (this.clientConfig.shouldOnDemandUpdateStatusChange()) {
this.applicationInfoManager.registerStatusChangeListener(this.statusChangeListener);
}
this.instanceInfoReplicator.start(this.clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
} else {
logger.info("Not registering with Eureka server per configuration");
}
}
private void cancelScheduledTasks() {
if (this.instanceInfoReplicator != null) {
this.instanceInfoReplicator.stop();
}
if (this.heartbeatExecutor != null) {
this.heartbeatExecutor.shutdownNow();
}
if (this.cacheRefreshExecutor != null) {
this.cacheRefreshExecutor.shutdownNow();
}
if (this.scheduler != null) {
this.scheduler.shutdownNow();
}
}
/** @deprecated */
@Deprecated
public List getServiceUrlsFromDNS(String instanceZone, boolean preferSameZone) {
return EndpointUtils.getServiceUrlsFromDNS(this.clientConfig, instanceZone, preferSameZone, this.urlRandomizer);
}
/** @deprecated */
@Deprecated
public List getDiscoveryServiceUrls(String zone) {
return EndpointUtils.getDiscoveryServiceUrls(this.clientConfig, zone, this.urlRandomizer);
}
/** @deprecated */
@Deprecated
public static Set getEC2DiscoveryUrlsFromZone(String dnsName, DiscoveryUrlType type) {
return EndpointUtils.getEC2DiscoveryUrlsFromZone(dnsName, type);
}
void refreshInstanceInfo() {
this.applicationInfoManager.refreshDataCenterInfoIfRequired();
this.applicationInfoManager.refreshLeaseInfoIfRequired();
InstanceStatus status;
try {
status = this.getHealthCheckHandler().getStatus(this.instanceInfo.getStatus());
} catch (Exception var3) {
logger.warn("Exception from healthcheckHandler.getStatus, setting status to DOWN", var3);
status = InstanceStatus.DOWN;
}
if (null != status) {
this.applicationInfoManager.setInstanceStatus(status);
}
}
@VisibleForTesting
InstanceInfoReplicator getInstanceInfoReplicator() {
return this.instanceInfoReplicator;
}
@VisibleForTesting
InstanceInfo getInstanceInfo() {
return this.instanceInfo;
}
public HealthCheckHandler getHealthCheckHandler() {
HealthCheckHandler healthCheckHandler = (HealthCheckHandler)this.healthCheckHandlerRef.get();
if (healthCheckHandler == null) {
if (null != this.healthCheckHandlerProvider) {
healthCheckHandler = (HealthCheckHandler)this.healthCheckHandlerProvider.get();
} else if (null != this.healthCheckCallbackProvider) {
healthCheckHandler = new HealthCheckCallbackToHandlerBridge((HealthCheckCallback)this.healthCheckCallbackProvider.get());
}
if (null == healthCheckHandler) {
healthCheckHandler = new HealthCheckCallbackToHandlerBridge((HealthCheckCallback)null);
}
this.healthCheckHandlerRef.compareAndSet((Object)null, healthCheckHandler);
}
return (HealthCheckHandler)this.healthCheckHandlerRef.get();
}
@VisibleForTesting
void refreshRegistry() {
try {
boolean isFetchingRemoteRegionRegistries = this.isFetchingRemoteRegionRegistries();
boolean remoteRegionsModified = false;
String latestRemoteRegions = this.clientConfig.fetchRegistryForRemoteRegions();
if (null != latestRemoteRegions) {
String currentRemoteRegions = (String)this.remoteRegionsToFetch.get();
if (!latestRemoteRegions.equals(currentRemoteRegions)) {
synchronized(this.instanceRegionChecker.getAzToRegionMapper()) {
if (this.remoteRegionsToFetch.compareAndSet(currentRemoteRegions, latestRemoteRegions)) {
String[] remoteRegions = latestRemoteRegions.split(",");
this.remoteRegionsRef.set(remoteRegions);
this.instanceRegionChecker.getAzToRegionMapper().setRegionsToFetch(remoteRegions);
remoteRegionsModified = true;
} else {
logger.info("Remote regions to fetch modified concurrently, ignoring change from {} to {}", currentRemoteRegions, latestRemoteRegions);
}
}
} else {
this.instanceRegionChecker.getAzToRegionMapper().refreshMapping();
}
}
boolean success = this.fetchRegistry(remoteRegionsModified);
if (success) {
this.registrySize = ((Applications)this.localRegionApps.get()).size();
this.lastSuccessfulRegistryFetchTimestamp = System.currentTimeMillis();
}
if (logger.isDebugEnabled()) {
StringBuilder allAppsHashCodes = new StringBuilder();
allAppsHashCodes.append("Local region apps hashcode: ");
allAppsHashCodes.append(((Applications)this.localRegionApps.get()).getAppsHashCode());
allAppsHashCodes.append(", is fetching remote regions? ");
allAppsHashCodes.append(isFetchingRemoteRegionRegistries);
Iterator var11 = this.remoteRegionVsApps.entrySet().iterator();
while(var11.hasNext()) {
Entry entry = (Entry)var11.next();
allAppsHashCodes.append(", Remote region: ");
allAppsHashCodes.append((String)entry.getKey());
allAppsHashCodes.append(" , apps hashcode: ");
allAppsHashCodes.append(((Applications)entry.getValue()).getAppsHashCode());
}
logger.debug("Completed cache refresh task for discovery. All Apps hash code is {} ", allAppsHashCodes);
}
} catch (Throwable var9) {
logger.error("Cannot fetch registry from server", var9);
}
}
private void fetchRegistryFromBackup() {
try {
BackupRegistry backupRegistryInstance = this.newBackupRegistryInstance();
if (null == backupRegistryInstance) {
backupRegistryInstance = (BackupRegistry)this.backupRegistryProvider.get();
}
if (null != backupRegistryInstance) {
Applications apps = null;
if (this.isFetchingRemoteRegionRegistries()) {
String remoteRegionsStr = (String)this.remoteRegionsToFetch.get();
if (null != remoteRegionsStr) {
apps = backupRegistryInstance.fetchRegistry(remoteRegionsStr.split(","));
}
} else {
apps = backupRegistryInstance.fetchRegistry();
}
if (apps != null) {
Applications applications = this.filterAndShuffle(apps);
applications.setAppsHashCode(applications.getReconcileHashCode());
this.localRegionApps.set(applications);
this.logTotalInstances();
logger.info("Fetched registry successfully from the backup");
}
} else {
logger.warn("No backup registry instance defined & unable to find any discovery servers.");
}
} catch (Throwable var4) {
logger.warn("Cannot fetch applications from apps although backup registry was specified", var4);
}
}
/** @deprecated */
@Deprecated
@Nullable
protected BackupRegistry newBackupRegistryInstance() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
return null;
}
private Applications filterAndShuffle(Applications apps) {
if (apps != null) {
if (this.isFetchingRemoteRegionRegistries()) {
Map remoteRegionVsApps = new ConcurrentHashMap();
apps.shuffleAndIndexInstances(remoteRegionVsApps, this.clientConfig, this.instanceRegionChecker);
Iterator var3 = remoteRegionVsApps.values().iterator();
while(var3.hasNext()) {
Applications applications = (Applications)var3.next();
applications.shuffleInstances(this.clientConfig.shouldFilterOnlyUpInstances());
}
this.remoteRegionVsApps = remoteRegionVsApps;
} else {
apps.shuffleInstances(this.clientConfig.shouldFilterOnlyUpInstances());
}
}
return apps;
}
private boolean isFetchingRemoteRegionRegistries() {
return null != this.remoteRegionsToFetch.get();
}
protected void onRemoteStatusChanged(InstanceStatus oldStatus, InstanceStatus newStatus) {
this.fireEvent(new StatusChangeEvent(oldStatus, newStatus));
}
protected void onCacheRefreshed() {
this.fireEvent(new CacheRefreshedEvent());
}
protected void fireEvent(EurekaEvent event) {
Iterator var2 = this.eventListeners.iterator();
while(var2.hasNext()) {
EurekaEventListener listener = (EurekaEventListener)var2.next();
try {
listener.onEvent(event);
} catch (Exception var5) {
logger.info("Event {} throw an exception for listener {}", new Object[]{event, listener, var5.getMessage()});
}
}
}
/** @deprecated */
@Deprecated
public static String getZone(InstanceInfo myInfo) {
String[] availZones = staticClientConfig.getAvailabilityZones(staticClientConfig.getRegion());
return InstanceInfo.getZone(availZones, myInfo);
}
/** @deprecated */
@Deprecated
public static String getRegion() {
String region = staticClientConfig.getRegion();
if (region == null) {
region = "default";
}
region = region.trim().toLowerCase();
return region;
}
/** @deprecated */
@Deprecated
public static List getEurekaServiceUrlsFromConfig(String instanceZone, boolean preferSameZone) {
return EndpointUtils.getServiceUrlsFromConfig(staticClientConfig, instanceZone, preferSameZone);
}
public long getLastSuccessfulHeartbeatTimePeriod() {
return this.lastSuccessfulHeartbeatTimestamp < 0L ? this.lastSuccessfulHeartbeatTimestamp : System.currentTimeMillis() - this.lastSuccessfulHeartbeatTimestamp;
}
public long getLastSuccessfulRegistryFetchTimePeriod() {
return this.lastSuccessfulRegistryFetchTimestamp < 0L ? this.lastSuccessfulRegistryFetchTimestamp : System.currentTimeMillis() - this.lastSuccessfulRegistryFetchTimestamp;
}
@Monitor(
name = "eurekaClient.registration.lastSuccessfulHeartbeatTimePeriod",
description = "How much time has passed from last successful heartbeat",
type = DataSourceType.GAUGE
)
private long getLastSuccessfulHeartbeatTimePeriodInternal() {
long delay = this.clientConfig.shouldRegisterWithEureka() && !this.isShutdown.get() ? this.getLastSuccessfulHeartbeatTimePeriod() : 0L;
this.heartbeatStalenessMonitor.update(this.computeStalenessMonitorDelay(delay));
return delay;
}
@Monitor(
name = "eurekaClient.registry.lastSuccessfulRegistryFetchTimePeriod",
description = "How much time has passed from last successful local registry update",
type = DataSourceType.GAUGE
)
private long getLastSuccessfulRegistryFetchTimePeriodInternal() {
long delay = this.clientConfig.shouldFetchRegistry() && !this.isShutdown.get() ? this.getLastSuccessfulRegistryFetchTimePeriod() : 0L;
this.registryStalenessMonitor.update(this.computeStalenessMonitorDelay(delay));
return delay;
}
@Monitor(
name = "eurekaClient.registry.localRegistrySize",
description = "Count of instances in the local registry",
type = DataSourceType.GAUGE
)
public int localRegistrySize() {
return this.registrySize;
}
private long computeStalenessMonitorDelay(long delay) {
return delay < 0L ? System.currentTimeMillis() - this.initTimestampMs : delay;
}
class CacheRefreshThread implements Runnable {
CacheRefreshThread() {
}
public void run() {
DiscoveryClient.this.refreshRegistry();
}
}
private class HeartbeatThread implements Runnable {
private HeartbeatThread() {
}
public void run() {
if (DiscoveryClient.this.renew()) {
DiscoveryClient.this.lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
}
}
}
}
//续约
boolean register() throws Throwable {
logger.info("DiscoveryClient_{}: registering service...", this.appPathIdentifier);
EurekaHttpResponse httpResponse;
try {
httpResponse = this.eurekaTransport.registrationClient.register(this.instanceInfo);
} catch (Exception var3) {
logger.warn("DiscoveryClient_{} - registration failed {}", new Object[]{this.appPathIdentifier, var3.getMessage(), var3});
throw var3;
}
if (logger.isInfoEnabled()) {
logger.info("DiscoveryClient_{} - registration status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
}
return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();
}
//续约
boolean renew() {
try {
EurekaHttpResponse httpResponse = this.eurekaTransport.registrationClient.sendHeartBeat(this.instanceInfo.getAppName(), this.instanceInfo.getId(), this.instanceInfo, (InstanceStatus)null);
logger.debug("DiscoveryClient_{} - Heartbeat status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) {
this.REREGISTER_COUNTER.increment();
logger.info("DiscoveryClient_{} - Re-registering apps/{}", this.appPathIdentifier, this.instanceInfo.getAppName());
long timestamp = this.instanceInfo.setIsDirtyWithTime();
boolean success = this.register();
if (success) {
this.instanceInfo.unsetIsDirty(timestamp);
}
return success;
} else {
return httpResponse.getStatusCode() == Status.OK.getStatusCode();
}
} catch (Throwable var5) {
logger.error("DiscoveryClient_{} - was unable to send heartbeat!", this.appPathIdentifier, var5);
return false;
}
}
//下线
@PreDestroy
public synchronized void shutdown() {
if (this.isShutdown.compareAndSet(false, true)) {
logger.info("Shutting down DiscoveryClient ...");
if (this.statusChangeListener != null && this.applicationInfoManager != null) {
this.applicationInfoManager.unregisterStatusChangeListener(this.statusChangeListener.getId());
}
this.cancelScheduledTasks();
if (this.applicationInfoManager != null && this.clientConfig.shouldRegisterWithEureka() && this.clientConfig.shouldUnregisterOnShutdown()) {
this.applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN);
this.unregister();
}
if (this.eurekaTransport != null) {
this.eurekaTransport.shutdown();
}
this.heartbeatStalenessMonitor.shutdown();
this.registryStalenessMonitor.shutdown();
logger.info("Completed shut down of DiscoveryClient");
}
}
//下线
void unregister() {
if (this.eurekaTransport != null && this.eurekaTransport.registrationClient != null) {
try {
logger.info("Unregistering ...");
EurekaHttpResponse httpResponse = this.eurekaTransport.registrationClient.cancel(this.instanceInfo.getAppName(), this.instanceInfo.getId());
logger.info("DiscoveryClient_{} - deregister status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
} catch (Exception var2) {
logger.error("DiscoveryClient_{} - de-registration failed{}", new Object[]{this.appPathIdentifier, var2.getMessage(), var2});
}
}
}
//获取注册信息到本地
private boolean fetchRegistry(boolean forceFullRegistryFetch) {
Stopwatch tracer = this.FETCH_REGISTRY_TIMER.start();
label122: {
boolean var4;
try {
Applications applications = this.getApplications();
if (!this.clientConfig.shouldDisableDelta() && Strings.isNullOrEmpty(this.clientConfig.getRegistryRefreshSingleVipAddress()) && !forceFullRegistryFetch && applications != null && applications.getRegisteredApplications().size() != 0 && applications.getVersion() != -1L) {
//增量保存
this.getAndUpdateDelta(applications);
} else {
//全量保存
logger.info("Disable delta property : {}", this.clientConfig.shouldDisableDelta());
logger.info("Single vip registry refresh property : {}", this.clientConfig.getRegistryRefreshSingleVipAddress());
logger.info("Force full registry fetch : {}", forceFullRegistryFetch);
logger.info("Application is null : {}", applications == null);
logger.info("Registered Applications size is zero : {}", applications.getRegisteredApplications().size() == 0);
logger.info("Application version is -1: {}", applications.getVersion() == -1L);
this.getAndStoreFullRegistry();
}
applications.setAppsHashCode(applications.getReconcileHashCode());
this.logTotalInstances();
break label122;
} catch (Throwable var8) {
logger.error("DiscoveryClient_{} - was unable to refresh its cache! status = {}", new Object[]{this.appPathIdentifier, var8.getMessage(), var8});
var4 = false;
} finally {
if (tracer != null) {
tracer.stop();
}
}
return var4;
}
this.onCacheRefreshed();
this.updateInstanceRemoteStatus();
return true;
}
DiscoveryClient.this.refreshRegistry():刷新注册信息到本地
class CacheRefreshThread implements Runnable {
CacheRefreshThread() {
}
public void run() {
DiscoveryClient.this.refreshRegistry();
}
}
...
@VisibleForTesting
void refreshRegistry() {
try {
boolean isFetchingRemoteRegionRegistries = this.isFetchingRemoteRegionRegistries();
boolean remoteRegionsModified = false;
String latestRemoteRegions = this.clientConfig.fetchRegistryForRemoteRegions();
if (null != latestRemoteRegions) {
String currentRemoteRegions = (String)this.remoteRegionsToFetch.get();
if (!latestRemoteRegions.equals(currentRemoteRegions)) {
synchronized(this.instanceRegionChecker.getAzToRegionMapper()) {
if (this.remoteRegionsToFetch.compareAndSet(currentRemoteRegions, latestRemoteRegions)) {
String[] remoteRegions = latestRemoteRegions.split(",");
this.remoteRegionsRef.set(remoteRegions);
this.instanceRegionChecker.getAzToRegionMapper().setRegionsToFetch(remoteRegions);
remoteRegionsModified = true;
} else {
logger.info("Remote regions to fetch modified concurrently, ignoring change from {} to {}", currentRemoteRegions, latestRemoteRegions);
}
}
} else {
this.instanceRegionChecker.getAzToRegionMapper().refreshMapping();
}
}
//获取注册信息从服务端
boolean success = this.fetchRegistry(remoteRegionsModified);
if (success) {
this.registrySize = ((Applications)this.localRegionApps.get()).size();
this.lastSuccessfulRegistryFetchTimestamp = System.currentTimeMillis();
}
if (logger.isDebugEnabled()) {
StringBuilder allAppsHashCodes = new StringBuilder();
allAppsHashCodes.append("Local region apps hashcode: ");
allAppsHashCodes.append(((Applications)this.localRegionApps.get()).getAppsHashCode());
allAppsHashCodes.append(", is fetching remote regions? ");
allAppsHashCodes.append(isFetchingRemoteRegionRegistries);
Iterator var11 = this.remoteRegionVsApps.entrySet().iterator();
while(var11.hasNext()) {
Entry entry = (Entry)var11.next();
allAppsHashCodes.append(", Remote region: ");
allAppsHashCodes.append((String)entry.getKey());
allAppsHashCodes.append(" , apps hashcode: ");
allAppsHashCodes.append(((Applications)entry.getValue()).getAppsHashCode());
}
logger.debug("Completed cache refresh task for discovery. All Apps hash code is {} ", allAppsHashCodes);
}
} catch (Throwable var9) {
logger.error("Cannot fetch registry from server", var9);
}
}
private boolean fetchRegistry(boolean forceFullRegistryFetch) {
Stopwatch tracer = this.FETCH_REGISTRY_TIMER.start();
label122: {
boolean var4;
try {
Applications applications = this.getApplications();
if (!this.clientConfig.shouldDisableDelta() && Strings.isNullOrEmpty(this.clientConfig.getRegistryRefreshSingleVipAddress()) && !forceFullRegistryFetch && applications != null && applications.getRegisteredApplications().size() != 0 && applications.getVersion() != -1L) {
//增量保存
this.getAndUpdateDelta(applications);
} else {
logger.info("Disable delta property : {}", this.clientConfig.shouldDisableDelta());
logger.info("Single vip registry refresh property : {}", this.clientConfig.getRegistryRefreshSingleVipAddress());
logger.info("Force full registry fetch : {}", forceFullRegistryFetch);
logger.info("Application is null : {}", applications == null);
logger.info("Registered Applications size is zero : {}", applications.getRegisteredApplications().size() == 0);
logger.info("Application version is -1: {}", applications.getVersion() == -1L);
//全量保存
this.getAndStoreFullRegistry();
}
applications.setAppsHashCode(applications.getReconcileHashCode());
this.logTotalInstances();
break label122;
} catch (Throwable var8) {
logger.error("DiscoveryClient_{} - was unable to refresh its cache! status = {}", new Object[]{this.appPathIdentifier, var8.getMessage(), var8});
var4 = false;
} finally {
if (tracer != null) {
tracer.stop();
}
}
return var4;
}
this.onCacheRefreshed();
this.updateInstanceRemoteStatus();
return true;
}
//增量保存
private void getAndUpdateDelta(Applications applications) throws Throwable {
long currentUpdateGeneration = this.fetchRegistryGeneration.get();
Applications delta = null;
//发送请求到服务端
EurekaHttpResponse httpResponse = this.eurekaTransport.queryClient.getDelta((String[])this.remoteRegionsRef.get());
if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
delta = (Applications)httpResponse.getEntity();
}
if (delta == null) {
logger.warn("The server does not allow the delta revision to be applied because it is not safe. Hence got the full registry.");
this.getAndStoreFullRegistry();
} else if (this.fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1L)) {
logger.debug("Got delta update with apps hashcode {}", delta.getAppsHashCode());
String reconcileHashCode = "";
if (this.fetchRegistryUpdateLock.tryLock()) {
try {
this.updateDelta(delta);
reconcileHashCode = this.getReconcileHashCode(applications);
} finally {
this.fetchRegistryUpdateLock.unlock();
}
} else {
logger.warn("Cannot acquire update lock, aborting getAndUpdateDelta");
}
if (!reconcileHashCode.equals(delta.getAppsHashCode()) || this.clientConfig.shouldLogDeltaDiff()) {
this.reconcileAndLogDifference(delta, reconcileHashCode);
}
} else {
logger.warn("Not updating application delta as another thread is updating it already");
logger.debug("Ignoring delta update with apps hashcode {}, as another thread is updating it already", delta.getAppsHashCode());
}
}
//全量保存
private void getAndStoreFullRegistry() throws Throwable {
long currentUpdateGeneration = this.fetchRegistryGeneration.get();
logger.info("Getting all instance registry info from the eureka server");
Applications apps = null;
//发送请求到服务端
EurekaHttpResponse httpResponse = this.clientConfig.getRegistryRefreshSingleVipAddress() == null ? this.eurekaTransport.queryClient.getApplications((String[])this.remoteRegionsRef.get()) : this.eurekaTransport.queryClient.getVip(this.clientConfig.getRegistryRefreshSingleVipAddress(), (String[])this.remoteRegionsRef.get());
if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
apps = (Applications)httpResponse.getEntity();
}
logger.info("The response status is {}", httpResponse.getStatusCode());
if (apps == null) {
logger.error("The application is null for some reason. Not storing this information");
} else if (this.fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1L)) {
this.localRegionApps.set(this.filterAndShuffle(apps));
logger.debug("Got full registry with apps hashcode {}", apps.getAppsHashCode());
} else {
logger.warn("Not updating applications as another thread is updating it already");
}
}
private class HeartbeatThread implements Runnable {
private HeartbeatThread() {
}
public void run() {
if (DiscoveryClient.this.renew()) {
DiscoveryClient.this.lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
}
}
}
...
boolean renew() {
try {
//发送心跳请求到服务端
EurekaHttpResponse httpResponse = this.eurekaTransport.registrationClient.sendHeartBeat(this.instanceInfo.getAppName(), this.instanceInfo.getId(), this.instanceInfo, (InstanceStatus)null);
logger.debug("DiscoveryClient_{} - Heartbeat status: {}", this.appPathIdentifier, httpResponse.getStatusCode());
//返回失败则再次注册
if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) {
this.REREGISTER_COUNTER.increment();
logger.info("DiscoveryClient_{} - Re-registering apps/{}", this.appPathIdentifier, this.instanceInfo.getAppName());
long timestamp = this.instanceInfo.setIsDirtyWithTime();
boolean success = this.register();
if (success) {
this.instanceInfo.unsetIsDirty(timestamp);
}
return success;
} else {
return httpResponse.getStatusCode() == Status.OK.getStatusCode();
}
} catch (Throwable var5) {
logger.error("DiscoveryClient_{} - was unable to send heartbeat!", this.appPathIdentifier, var5);
return false;
}
}
class InstanceInfoReplicator implements Runnable {
...
InstanceInfoReplicator(DiscoveryClient discoveryClient, InstanceInfo instanceInfo, int replicationIntervalSeconds, int burstSize) {
this.discoveryClient = discoveryClient;
this.instanceInfo = instanceInfo;
this.scheduler = Executors.newScheduledThreadPool(1, (new ThreadFactoryBuilder()).setNameFormat("DiscoveryClient-InstanceInfoReplicator-%d").setDaemon(true).build());
this.scheduledPeriodicRef = new AtomicReference();
this.started = new AtomicBoolean(false);
this.rateLimiter = new RateLimiter(TimeUnit.MINUTES);
this.replicationIntervalSeconds = replicationIntervalSeconds;
this.burstSize = burstSize;
this.allowedRatePerMinute = 60 * this.burstSize / this.replicationIntervalSeconds;
logger.info("InstanceInfoReplicator onDemand update allowed rate per min is {}", this.allowedRatePerMinute);
}
public void start(int initialDelayMs) {
if (this.started.compareAndSet(false, true)) {
this.instanceInfo.setIsDirty();
Future next = this.scheduler.schedule(this, (long)initialDelayMs, TimeUnit.SECONDS);
this.scheduledPeriodicRef.set(next);
}
}
public void stop() {
this.shutdownAndAwaitTermination(this.scheduler);
this.started.set(false);
}
private void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown();
try {
if (!pool.awaitTermination(3L, TimeUnit.SECONDS)) {
pool.shutdownNow();
}
} catch (InterruptedException var3) {
logger.warn("InstanceInfoReplicator stop interrupted");
}
}
public boolean onDemandUpdate() {
if (this.rateLimiter.acquire(this.burstSize, (long)this.allowedRatePerMinute)) {
if (!this.scheduler.isShutdown()) {
this.scheduler.submit(new Runnable() {
public void run() {
InstanceInfoReplicator.logger.debug("Executing on-demand update of local InstanceInfo");
Future latestPeriodic = (Future)InstanceInfoReplicator.this.scheduledPeriodicRef.get();
if (latestPeriodic != null && !latestPeriodic.isDone()) {
InstanceInfoReplicator.logger.debug("Canceling the latest scheduled update, it will be rescheduled at the end of on demand update");
latestPeriodic.cancel(false);
}
InstanceInfoReplicator.this.run();
}
});
return true;
} else {
logger.warn("Ignoring onDemand update due to stopped scheduler");
return false;
}
} else {
logger.warn("Ignoring onDemand update due to rate limiter");
return false;
}
}
public void run() {
boolean var6 = false;
ScheduledFuture next;
label53: {
try {
var6 = true;
//更新注册中心地址信息
//更新续约信息等
this.discoveryClient.refreshInstanceInfo();
Long dirtyTimestamp = this.instanceInfo.isDirtyWithTime();
if (dirtyTimestamp != null) {
this.discoveryClient.register();
this.instanceInfo.unsetIsDirty(dirtyTimestamp);
var6 = false;
} else {
var6 = false;
}
break label53;
} catch (Throwable var7) {
logger.warn("There was a problem with the instance info replicator", var7);
var6 = false;
} finally {
if (var6) {
ScheduledFuture next = this.scheduler.schedule(this, (long)this.replicationIntervalSeconds, TimeUnit.SECONDS);
this.scheduledPeriodicRef.set(next);
}
}
next = this.scheduler.schedule(this, (long)this.replicationIntervalSeconds, TimeUnit.SECONDS);
this.scheduledPeriodicRef.set(next);
return;
}
next = this.scheduler.schedule(this, (long)this.replicationIntervalSeconds, TimeUnit.SECONDS);
this.scheduledPeriodicRef.set(next);
}
}
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass({EurekaClientConfig.class})
@ConditionalOnProperty(
value = {"eureka.client.enabled"},
matchIfMissing = true
)
@ConditionalOnDiscoveryEnabled //eueka discovery client配置
public class EurekaDiscoveryClientConfiguration {
...
@Bean
public EurekaDiscoveryClientConfiguration.Marker eurekaDiscoverClientMarker() {
return new EurekaDiscoveryClientConfiguration.Marker();
}
//依赖spring Listener
@Configuration
@ConditionalOnClass({RefreshScopeRefreshedEvent.class})
protected static class EurekaClientConfigurationRefresher implements ApplicationListener {
@Autowired(
required = false
)
private EurekaClient eurekaClient;
@Autowired(
required = false
)
private EurekaAutoServiceRegistration autoRegistration;
protected EurekaClientConfigurationRefresher() {
}
//自动刷新
public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
if (this.eurekaClient != null) {
this.eurekaClient.getApplications();
}
if (this.autoRegistration != null) {
this.autoRegistration.stop();
this.autoRegistration.start();
}
}
}
class Marker {
Marker() {
}
}
//健康检查
@Configuration
@ConditionalOnProperty(
value = {"eureka.client.healthcheck.enabled"},
matchIfMissing = false
)
protected static class EurekaHealthCheckHandlerConfiguration {
@Autowired(
required = false
)
private HealthAggregator healthAggregator = new OrderedHealthAggregator();
protected EurekaHealthCheckHandlerConfiguration() {
}
@Bean
@ConditionalOnMissingBean({HealthCheckHandler.class})
public EurekaHealthCheckHandler eurekaHealthCheckHandler() {
return new EurekaHealthCheckHandler(this.healthAggregator);
}
}
}
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass({EurekaClientConfig.class})
@Import({DiscoveryClientOptionalArgsConfiguration.class})
@ConditionalOnBean({Marker.class})
@ConditionalOnProperty(
value = {"eureka.client.enabled"},
matchIfMissing = true
)
@ConditionalOnDiscoveryEnabled
@AutoConfigureBefore({NoopDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class})
@AutoConfigureAfter( //之后在实例EurekaDiscoveryClientConfiguration
name = {"org.springframework.cloud.autoconfigure.RefreshAutoConfiguration", "org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration", "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"}
)
public class EurekaClientAutoConfiguration {
private ConfigurableEnvironment env;
public EurekaClientAutoConfiguration(ConfigurableEnvironment env) {
this.env = env;
}
@Bean
public HasFeatures eurekaFeature() {
return HasFeatures.namedFeature("Eureka Client", EurekaClient.class);
}
@Bean
@ConditionalOnMissingBean(
value = {EurekaClientConfig.class},
search = SearchStrategy.CURRENT
)
public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) {
//EurekaClientConfigBean配置初始化
EurekaClientConfigBean client = new EurekaClientConfigBean();
if ("bootstrap".equals(this.env.getProperty("spring.config.name"))) {
client.setRegisterWithEureka(false);
}
return client;
}
@Bean
@ConditionalOnMissingBean
public ManagementMetadataProvider serviceManagementMetadataProvider() {
return new DefaultManagementMetadataProvider();
}
private String getProperty(String property) {
return this.env.containsProperty(property) ? this.env.getProperty(property) : "";
}
@Bean
@ConditionalOnMissingBean(
value = {EurekaInstanceConfig.class},
search = SearchStrategy.CURRENT
)
public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) {
//EurekaInstanceConfigBean实例初始化数据
String hostname = this.getProperty("eureka.instance.hostname");
boolean preferIpAddress = Boolean.parseBoolean(this.getProperty("eureka.instance.prefer-ip-address"));
String ipAddress = this.getProperty("eureka.instance.ip-address");
boolean isSecurePortEnabled = Boolean.parseBoolean(this.getProperty("eureka.instance.secure-port-enabled"));
String serverContextPath = this.env.getProperty("server.servlet.context-path", "/");
int serverPort = Integer.valueOf(this.env.getProperty("server.port", this.env.getProperty("port", "8080")));
Integer managementPort = (Integer)this.env.getProperty("management.server.port", Integer.class);
String managementContextPath = this.env.getProperty("management.server.servlet.context-path");
Integer jmxPort = (Integer)this.env.getProperty("com.sun.management.jmxremote.port", Integer.class);
EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
instance.setNonSecurePort(serverPort);
instance.setInstanceId(IdUtils.getDefaultInstanceId(this.env));
instance.setPreferIpAddress(preferIpAddress);
instance.setSecurePortEnabled(isSecurePortEnabled);
if (StringUtils.hasText(ipAddress)) {
instance.setIpAddress(ipAddress);
}
if (isSecurePortEnabled) {
instance.setSecurePort(serverPort);
}
if (StringUtils.hasText(hostname)) {
instance.setHostname(hostname);
}
String statusPageUrlPath = this.getProperty("eureka.instance.status-page-url-path");
String healthCheckUrlPath = this.getProperty("eureka.instance.health-check-url-path");
if (StringUtils.hasText(statusPageUrlPath)) {
instance.setStatusPageUrlPath(statusPageUrlPath);
}
if (StringUtils.hasText(healthCheckUrlPath)) {
instance.setHealthCheckUrlPath(healthCheckUrlPath);
}
ManagementMetadata metadata = managementMetadataProvider.get(instance, serverPort, serverContextPath, managementContextPath, managementPort);
if (metadata != null) {
instance.setStatusPageUrl(metadata.getStatusPageUrl());
instance.setHealthCheckUrl(metadata.getHealthCheckUrl());
if (instance.isSecurePortEnabled()) {
instance.setSecureHealthCheckUrl(metadata.getSecureHealthCheckUrl());
}
Map metadataMap = instance.getMetadataMap();
metadataMap.computeIfAbsent("management.port", (k) -> {
return String.valueOf(metadata.getManagementPort());
});
} else if (StringUtils.hasText(managementContextPath)) {
instance.setHealthCheckUrlPath(managementContextPath + instance.getHealthCheckUrlPath());
instance.setStatusPageUrlPath(managementContextPath + instance.getStatusPageUrlPath());
}
this.setupJmxPort(instance, jmxPort);
return instance;
}
private void setupJmxPort(EurekaInstanceConfigBean instance, Integer jmxPort) {
Map metadataMap = instance.getMetadataMap();
if (metadataMap.get("jmx.port") == null && jmxPort != null) {
metadataMap.put("jmx.port", String.valueOf(jmxPort));
}
}
//EurekaDiscoveryClient实例化
@Bean
public DiscoveryClient discoveryClient(EurekaClient client, EurekaClientConfig clientConfig) {
return new EurekaDiscoveryClient(client, clientConfig);
}
//EurekaDiscoveryClient实例化
@Bean
public EurekaServiceRegistry eurekaServiceRegistry() {
return new EurekaServiceRegistry();
}
//自动注册
@Bean
@ConditionalOnBean({AutoServiceRegistrationProperties.class})
@ConditionalOnProperty(
value = {"spring.cloud.service-registry.auto-registration.enabled"},
matchIfMissing = true
)
public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry registry, EurekaRegistration registration) {
return new EurekaAutoServiceRegistration(context, registry, registration);
}
@Configuration
@ConditionalOnClass({Health.class})
protected static class EurekaHealthIndicatorConfiguration {
protected EurekaHealthIndicatorConfiguration() {
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledHealthIndicator("eureka")
public EurekaHealthIndicator eurekaHealthIndicator(EurekaClient eurekaClient, EurekaInstanceConfig instanceConfig, EurekaClientConfig clientConfig) {
return new EurekaHealthIndicator(eurekaClient, instanceConfig, clientConfig);
}
}
private static class OnMissingRefreshScopeCondition extends AnyNestedCondition {
OnMissingRefreshScopeCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnProperty(
value = {"eureka.client.refresh.enable"},
havingValue = "false"
)
static class OnPropertyDisabled {
OnPropertyDisabled() {
}
}
@ConditionalOnMissingBean({RefreshAutoConfiguration.class})
static class MissingScope {
MissingScope() {
}
}
@ConditionalOnMissingClass({"org.springframework.cloud.context.scope.refresh.RefreshScope"})
static class MissingClass {
MissingClass() {
}
}
}
//自动刷新实例化
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ConditionalOnClass({RefreshScope.class})
@ConditionalOnBean({RefreshAutoConfiguration.class})
@ConditionalOnProperty(
value = {"eureka.client.refresh.enable"},
havingValue = "true",
matchIfMissing = true
)
@interface ConditionalOnRefreshScope {
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({EurekaClientAutoConfiguration.OnMissingRefreshScopeCondition.class})
@interface ConditionalOnMissingRefreshScope {
}
@Configuration
@EurekaClientAutoConfiguration.ConditionalOnRefreshScope
protected static class RefreshableEurekaClientConfiguration {
@Autowired
private ApplicationContext context;
@Autowired
private AbstractDiscoveryClientOptionalArgs> optionalArgs;
protected RefreshableEurekaClientConfiguration() {
}
@Bean(
destroyMethod = "shutdown"
)
@ConditionalOnMissingBean(
value = {EurekaClient.class},
search = SearchStrategy.CURRENT
)
@org.springframework.cloud.context.config.annotation.RefreshScope
@Lazy
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config, EurekaInstanceConfig instance, @Autowired(required = false) HealthCheckHandler healthCheckHandler) {
ApplicationInfoManager appManager;
if (AopUtils.isAopProxy(manager)) {
appManager = (ApplicationInfoManager)ProxyUtils.getTargetObject(manager);
} else {
appManager = manager;
}
CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager, config, this.optionalArgs, this.context);
cloudEurekaClient.registerHealthCheck(healthCheckHandler);
return cloudEurekaClient;
}
@Bean
@ConditionalOnMissingBean(
value = {ApplicationInfoManager.class},
search = SearchStrategy.CURRENT
)
@org.springframework.cloud.context.config.annotation.RefreshScope
@Lazy
public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
InstanceInfo instanceInfo = (new InstanceInfoFactory()).create(config);
return new ApplicationInfoManager(config, instanceInfo);
}
@Bean
@org.springframework.cloud.context.config.annotation.RefreshScope
@ConditionalOnBean({AutoServiceRegistrationProperties.class})
@ConditionalOnProperty(
value = {"spring.cloud.service-registry.auto-registration.enabled"},
matchIfMissing = true
)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager, @Autowired(required = false) ObjectProvider healthCheckHandler) {
return EurekaRegistration.builder(instanceConfig).with(applicationInfoManager).with(eurekaClient).with(healthCheckHandler).build();
}
}
@Configuration
@EurekaClientAutoConfiguration.ConditionalOnMissingRefreshScope
protected static class EurekaClientConfiguration {
@Autowired
private ApplicationContext context;
@Autowired
private AbstractDiscoveryClientOptionalArgs> optionalArgs;
protected EurekaClientConfiguration() {
}
@Bean(
destroyMethod = "shutdown"
)
@ConditionalOnMissingBean(
value = {EurekaClient.class},
search = SearchStrategy.CURRENT
)
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config) {
return new CloudEurekaClient(manager, config, this.optionalArgs, this.context);
}
@Bean
@ConditionalOnMissingBean(
value = {ApplicationInfoManager.class},
search = SearchStrategy.CURRENT
)
public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
InstanceInfo instanceInfo = (new InstanceInfoFactory()).create(config);
return new ApplicationInfoManager(config, instanceInfo);
}
@Bean
@ConditionalOnBean({AutoServiceRegistrationProperties.class})
@ConditionalOnProperty(
value = {"spring.cloud.service-registry.auto-registration.enabled"},
matchIfMissing = true
)
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient, CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager, @Autowired(required = false) ObjectProvider healthCheckHandler) {
return EurekaRegistration.builder(instanceConfig).with(applicationInfoManager).with(eurekaClient).with(healthCheckHandler).build();
}
}
}
获取注册instances
public class EurekaDiscoveryClient implements DiscoveryClient {
public List getInstances(String serviceId) {
List infos = this.eurekaClient.getInstancesByVipAddress(serviceId, false);
List instances = new ArrayList();
Iterator var4 = infos.iterator();
while(var4.hasNext()) {
InstanceInfo info = (InstanceInfo)var4.next();
instances.add(new EurekaDiscoveryClient.EurekaServiceInstance(info));
}
return instances;
}
public List getServices() {
Applications applications = this.eurekaClient.getApplications();
if (applications == null) {
return Collections.emptyList();
} else {
List registered = applications.getRegisteredApplications();
List names = new ArrayList();
Iterator var4 = registered.iterator();
while(var4.hasNext()) {
Application app = (Application)var4.next();
if (!app.getInstances().isEmpty()) {
names.add(app.getName().toLowerCase());
}
}
return names;
}
}
...
}
在spring.factories中自动装配,对EurekaRibbonClientConfiguration实例化,详见eureka+robbin解析
@Configuration
public class EurekaRibbonClientConfiguration {
private static final Log log = LogFactory.getLog(EurekaRibbonClientConfiguration.class);
@Value("${ribbon.eureka.approximateZoneFromHostname:false}")
private boolean approximateZoneFromHostname = false;
@RibbonClientName
private String serviceId = "client";
...
@Bean
@ConditionalOnMissingBean
public IPing ribbonPing(IClientConfig config) {
if (this.propertiesFactory.isSet(IPing.class, this.serviceId)) {
return (IPing)this.propertiesFactory.get(IPing.class, config, this.serviceId);
} else {
NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
ping.initWithNiwsConfig(config);
return ping;
}
}
//实例化ribbonServerList,用于后续与网关通过robbin来获取ServerList列表
@Bean
@ConditionalOnMissingBean
public ServerList> ribbonServerList(IClientConfig config, Provider eurekaClientProvider) {
if (this.propertiesFactory.isSet(ServerList.class, this.serviceId)) {
return (ServerList)this.propertiesFactory.get(ServerList.class, config, this.serviceId);
} else {
DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(config, eurekaClientProvider);
DomainExtractingServerList serverList = new DomainExtractingServerList(discoveryServerList, config, this.approximateZoneFromHostname);
return serverList;
}
}
@Bean
public ServerIntrospector serverIntrospector() {
return new EurekaServerIntrospector();
}
//获取eureka地址
@PostConstruct
public void preprocess() {
String zone = ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone);
if (this.clientConfig != null && StringUtils.isEmpty(zone)) {
String availabilityZone;
if (this.approximateZoneFromHostname && this.eurekaConfig != null) {
availabilityZone = ZoneUtils.extractApproximateZone(this.eurekaConfig.getHostName(false));
log.debug("Setting Zone To " + availabilityZone);
ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone, availabilityZone);
} else {
availabilityZone = this.eurekaConfig == null ? null : (String)this.eurekaConfig.getMetadataMap().get("zone");
if (availabilityZone == null) {
String[] zones = this.clientConfig.getAvailabilityZones(this.clientConfig.getRegion());
availabilityZone = zones != null && zones.length > 0 ? zones[0] : null;
}
if (availabilityZone != null) {
ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone, availabilityZone);
}
}
}
RibbonUtils.initializeRibbonDefaults(this.serviceId);
}
}