SpringCloud版本Greenwich.SR2
使用注解@EnableDiscoveryClient,表明这是一个eureka客户端
我们来看一下为什么写了这个注解就可以注册到注册中心。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
/**
* If true, the ServiceRegistry will automatically register the local server.
* @return - {@code true} if you want to automatically register.
*/
boolean autoRegister() default true;
}
里面只有一个属性,autoRegister自动注册
引入了这个类EnableDiscoveryClientImportSelector
@Override
public String[] selectImports(AnnotationMetadata metadata) {
/**
* 将类上的需要导入的导入进来
*/
String[] imports = super.selectImports(metadata);
/**
*获取所有的属性,判断autoRegister自动注册是否打开
*/
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
boolean autoRegister = attributes.getBoolean("autoRegister");
/**
* 如果打开了自动注册
*/
if (autoRegister) {
List<String> importsList = new ArrayList<>(Arrays.asList(imports));
importsList.add(
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = importsList.toArray(new String[0]);
}
else {
Environment env = getEnvironment();
if (ConfigurableEnvironment.class.isInstance(env)) {
ConfigurableEnvironment configEnv = (ConfigurableEnvironment) env;
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("spring.cloud.service-registry.auto-registration.enabled", false);
MapPropertySource propertySource = new MapPropertySource(
"springCloudDiscoveryClient", map);
configEnv.getPropertySources().addLast(propertySource);
}
}
return imports;
}
心得tips:
- 不知道怎么看源码就debug比如在上面打断点,下一步就到这了
不扯远了,我们继续
那么EurekaClient是什么呢?
Eureka结构,关系
LookupService中定义的方法
/**
*通过appName获取Application
*/
Application getApplication(String appName);
/**
*获取所有的Application
*/
Applications getApplications();
/**
*通过id查找实例
*/
List<InstanceInfo> getInstancesById(String id);
InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure);
Application的结构
Application就是所有相同的appName对应的实例(InstanceInfo)
private static Random shuffleRandom = new Random();
@Override
public String toString() {
return "Application [name=" + name + ", isDirty=" + isDirty
+ ", instances=" + instances + ", shuffledInstances="
+ shuffledInstances + ", instancesMap=" + instancesMap + "]";
}
private String name;
/**
*是否为脏数据
*/
@XStreamOmitField
private volatile boolean isDirty = false;
/**
*所有的实例set
*/
@XStreamImplicit
private final Set<InstanceInfo> instances;
private final AtomicReference<List<InstanceInfo>> shuffledInstances;
/**
*instancesMap,key是实例id,InstanceInfo实例对象
*/
private final Map<String, InstanceInfo> instancesMap;
InstanceInfo结构对应的微服务的信息
起点EurekaClient
如果没有EurekaClient的话,会创建一个EurekaClient同时创建CloudEurekaClient以及父类DiscoveryClient
@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) {
// If we use the proxy of the ApplicationInfoManager we could run into a
// problem
// when shutdown is called on the CloudEurekaClient where the
// ApplicationInfoManager bean is
// requested but wont be allowed because we are shutting down. To avoid this
// we use the
// object directly.
ApplicationInfoManager appManager;
if (AopUtils.isAopProxy(manager)) {
appManager = ProxyUtils.getTargetObject(manager);
}
else {
appManager = manager;
}
//创建一个cloudEurekaClient,会创建一个父类(DiscoveryClient)
CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager,
config, this.optionalArgs, this.context);
cloudEurekaClient.registerHealthCheck(healthCheckHandler);
return cloudEurekaClient;
}
public CloudEurekaClient(ApplicationInfoManager applicationInfoManager,
EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs<?> args,
ApplicationEventPublisher publisher) {
super(applicationInfoManager, config, args);
this.applicationInfoManager = applicationInfoManager;
this.publisher = publisher;
this.eurekaTransportField = ReflectionUtils.findField(DiscoveryClient.class,
"eurekaTransport");
ReflectionUtils.makeAccessible(this.eurekaTransportField);
}
@Inject
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args,
Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer) {
//初始化一些需要用到的对象
if (args != null) {
this.healthCheckHandlerProvider = args.healthCheckHandlerProvider;
this.healthCheckCallbackProvider = args.healthCheckCallbackProvider;
this.eventListeners.addAll(args.getEventListeners());
this.preRegistrationHandler = args.preRegistrationHandler;
} else {
this.healthCheckCallbackProvider = null;
this.healthCheckHandlerProvider = null;
this.preRegistrationHandler = null;
}
//获取当前的实例
this.applicationInfoManager = applicationInfoManager;
InstanceInfo myInfo = applicationInfoManager.getInfo();
clientConfig = config;
staticClientConfig = clientConfig;
transportConfig = config.getTransportConfig();
instanceInfo = myInfo;
if (myInfo != null) {
appPathIdentifier = instanceInfo.getAppName() + "/" + instanceInfo.getId();
} else {
logger.warn("Setting instanceInfo to a passed in null value");
}
this.backupRegistryProvider = backupRegistryProvider;
this.endpointRandomizer = endpointRandomizer;
this.urlRandomizer = new EndpointUtils.InstanceInfoBasedUrlRandomizer(instanceInfo);
//localRegionApps保存的本地缓存,所有的应用列表
localRegionApps.set(new Applications());
//获取服务器的应用的标识,用于对比compareAndSet
fetchRegistryGeneration = new AtomicLong(0);
//获取可达的远程区域
remoteRegionsToFetch = new AtomicReference<String>(clientConfig.fetchRegistryForRemoteRegions());
remoteRegionsRef = new AtomicReference<>(remoteRegionsToFetch.get() == null ? null : remoteRegionsToFetch.get().split(","));
//如果允许获取应用列表,初始化应用列表监视器
if (config.shouldFetchRegistry()) {
this.registryStalenessMonitor = new ThresholdLevelsMetric(this, METRIC_REGISTRY_PREFIX + "lastUpdateSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
} else {
this.registryStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
}
//如果允许注册自己,初始化心跳状态监视器
if (config.shouldRegisterWithEureka()) {
this.heartbeatStalenessMonitor = new ThresholdLevelsMetric(this, METRIC_REGISTRATION_PREFIX + "lastHeartbeatSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L});
} else {
this.heartbeatStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC;
}
logger.info("Initializing Eureka in region {}", clientConfig.getRegion());
//如果既不允许注册也不允许获取
if (!config.shouldRegisterWithEureka() && !config.shouldFetchRegistry()) {
logger.info("Client configured to neither register nor query for data.");
scheduler = null;
heartbeatExecutor = null;
cacheRefreshExecutor = null;
eurekaTransport = null;
instanceRegionChecker = new InstanceRegionChecker(new PropertyBasedAzToRegionMapper(config), clientConfig.getRegion());
// This is a bit of hack to allow for existing code using DiscoveryManager.getInstance()
// to work with DI'd DiscoveryClient
DiscoveryManager.getInstance().setDiscoveryClient(this);
DiscoveryManager.getInstance().setEurekaClientConfig(config);
initTimestampMs = System.currentTimeMillis();
logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}",
initTimestampMs, this.getApplications().size());
return; // no need to setup up an network tasks and we are done
}
try {
//为心跳和缓存刷新创建线程池,创建定时任务线程池
// default size of 2 - 1 each for heartbeat and cacheRefresh
scheduler = Executors.newScheduledThreadPool(2,
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-%d")
.setDaemon(true)
.build());
heartbeatExecutor = new ThreadPoolExecutor(
1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-HeartbeatExecutor-%d")
.setDaemon(true)
.build()
); // use direct handoff
cacheRefreshExecutor = new ThreadPoolExecutor(
1, clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d")
.setDaemon(true)
.build()
); // use direct handoff
eurekaTransport = new EurekaTransport();
//TODO 服务器节点定时任务,以后分析
scheduleServerEndpointTask(eurekaTransport, args);
AzToRegionMapper azToRegionMapper;
if (clientConfig.shouldUseDnsForFetchingServiceUrls()) {
azToRegionMapper = new DNSBasedAzToRegionMapper(clientConfig);
} else {
azToRegionMapper = new PropertyBasedAzToRegionMapper(clientConfig);
}
if (null != remoteRegionsToFetch.get()) {
azToRegionMapper.setRegionsToFetch(remoteRegionsToFetch.get().split(","));
}
instanceRegionChecker = new InstanceRegionChecker(azToRegionMapper, clientConfig.getRegion());
} catch (Throwable e) {
throw new RuntimeException("Failed to initialize DiscoveryClient!", e);
}
if (clientConfig.shouldFetchRegistry() && !fetchRegistry(false)) {
fetchRegistryFromBackup();
}
// call and execute the pre registration handler before all background tasks (inc registration) is started
if (this.preRegistrationHandler != null) {
this.preRegistrationHandler.beforeRegistration();
}
if (clientConfig.shouldRegisterWithEureka() && clientConfig.shouldEnforceRegistrationAtInit()) {
try {
if (!register() ) {
throw new IllegalStateException("Registration error at startup. Invalid server response.");
}
} catch (Throwable th) {
logger.error("Registration error at startup: {}", th.getMessage());
throw new IllegalStateException(th);
}
}
//开启定时任务
// finally, init the schedule tasks (e.g. cluster resolvers, heartbeat, instanceInfo replicator, fetch
initScheduledTasks();
try {
//监视
Monitors.registerObject(this);
} catch (Throwable e) {
logger.warn("Cannot register timers", e);
}
// This is a bit of hack to allow for existing code using DiscoveryManager.getInstance()
// to work with DI'd DiscoveryClient
DiscoveryManager.getInstance().setDiscoveryClient(this);
DiscoveryManager.getInstance().setEurekaClientConfig(config);
initTimestampMs = System.currentTimeMillis();
logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}",
initTimestampMs, this.getApplications().size());
}
开启定时任务
- 缓存刷新定时任务
- 心跳检测定时任务
- 注册定时任务
private void initScheduledTasks() {
//更新间隔时间
int renewalIntervalInSecs;
int expBackOffBound;
//是否从服务器中获取注册列表
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);
}
//是否允许去服务器端注册自己
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()), (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) {
//如果状态变为down了
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");
}
}
缓存刷新的线程类
class CacheRefreshThread implements Runnable {
CacheRefreshThread() {
}
public void run() {
DiscoveryClient.this.refreshRegistry();
}
}
void refreshRegistry() {
try {
boolean isFetchingRemoteRegionRegistries = this.isFetchingRemoteRegionRegistries();
boolean remoteRegionsModified = false;
/**
* Comma separated list of regions for which the eureka registry information will be
* fetched. It is mandatory to define the availability zones for each of these regions
* as returned by availabilityZones. Failing to do so, will result in failure of
* discovery client startup.
* 这个地方通过debug知道,是获取的fetchRemoteRegionsRegistry属性,上方为属性的注释信息。
* 逗号分隔的eureka服务器地址(可以获取注册信息的)
* 经过翻译,我依然不知道干嘛的,所以开启debug模式
* 结论,eureka可以进行多区域配置,使用fetch-remote-regions-registry可以指定使用哪个区域
* 但是指定的区域必须是可达区域
* 例如
* eureka.client.availability-zones.eureka=eureka
* 区域名和区域值
* eureka.client.service-url.eureka=http://127.0.0.1:8888/eureka/
* 获取上次的远程区域
* 如果使用的是defaultZone(大家在项目中常用的配置latestRemoteRegions == null)
* 直接跳到下面
*/
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);
}
}
更新本地缓存方法,获取注册的应用信息
满足以下条件会去获取全量的注册信息
- delta is disabled
- 单独的vip地址
- 传入的参数要求全量
- localRegionApps本地的缓存是空
- localRegionApps大小为0
- localRegionApps版本为-1
/**
* Disable delta property : false
* Single vip registry refresh property : null
* Force full registry fetch : false
* Application is null : false
* Registered Applications size is zero : true
* Application version is -1: true
* 满足以下条件会去获取全量的注册信息
* 1.delta is disabled
* 2.单独的vip地址
* 3.传入的参数要求全量
* 4.localRegionApps本地的缓存是空
* 5.localRegionApps大小为0
* 6.localRegionApps版本为-1
*/
private boolean fetchRegistry(boolean forceFullRegistryFetch) {
Stopwatch tracer = FETCH_REGISTRY_TIMER.start();
try {
// If the delta is disabled or if it is the first time, get all
// applications
Applications applications = getApplications();
if (clientConfig.shouldDisableDelta()
|| (!Strings.isNullOrEmpty(clientConfig.getRegistryRefreshSingleVipAddress()))
|| forceFullRegistryFetch
|| (applications == null)
|| (applications.getRegisteredApplications().size() == 0)
|| (applications.getVersion() == -1)) //Client application does not have latest library supporting delta
{
logger.info("Disable delta property : {}", clientConfig.shouldDisableDelta());
logger.info("Single vip registry refresh property : {}", clientConfig.getRegistryRefreshSingleVipAddress());
logger.info("Force full registry fetch : {}", forceFullRegistryFetch);
logger.info("Application is null : {}", (applications == null));
logger.info("Registered Applications size is zero : {}",
(applications.getRegisteredApplications().size() == 0));
logger.info("Application version is -1: {}", (applications.getVersion() == -1));
getAndStoreFullRegistry();
} else {
getAndUpdateDelta(applications);
}
applications.setAppsHashCode(applications.getReconcileHashCode());
logTotalInstances();
} catch (Throwable e) {
logger.error(PREFIX + "{} - was unable to refresh its cache! status = {}", appPathIdentifier, e.getMessage(), e);
return false;
} finally {
if (tracer != null) {
tracer.stop();
}
}
/**
* 更新实例状态前通知缓存刷新
*/
onCacheRefreshed();
//基于缓存中刷新的数据,更新远程状态
updateInstanceRemoteStatus();
// registry was fetched successfully, so return true
return true;
}
全量更新可用实例的本地缓存
- 如果有vip地址,那么从vip地址中取,否则从默认中获取
- 乐观锁,防止其他线程重复更改
private void getAndStoreFullRegistry() throws Throwable {
//获取当前更新的版本
long currentUpdateGeneration = fetchRegistryGeneration.get();
logger.info("Getting all instance registry info from the eureka server");
Applications apps = null;
//如果有vip地址,那么从vip地址中取,否则从默认中获取
EurekaHttpResponse<Applications> httpResponse = clientConfig.getRegistryRefreshSingleVipAddress() == null
? eurekaTransport.queryClient.getApplications(remoteRegionsRef.get())
: eurekaTransport.queryClient.getVip(clientConfig.getRegistryRefreshSingleVipAddress(), remoteRegionsRef.get());
if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
apps = 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");
//乐观锁,cas,如果其他线程修改过,不作处理,记录日志
} else if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)) {
//更新本地缓存
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");
}
}
部分更新
- 从eureka服务器中获取指定的region的增量数据
- 如果没有数据,尝试全量更新
- 如果有数据,通过乐观锁控制版本
- 如果hash码不一致全量更新
private void getAndUpdateDelta(Applications applications) throws Throwable {
//获取更新版本
long currentUpdateGeneration = fetchRegistryGeneration.get();
Applications delta = null;
//从eureka服务器中获取指定的region的增量数据
EurekaHttpResponse<Applications> httpResponse = eurekaTransport.queryClient.getDelta(remoteRegionsRef.get());
if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {
delta = httpResponse.getEntity();
}
//如果没有数据,尝试全量更新
if (delta == null) {
logger.warn("The server does not allow the delta revision to be applied because it is not safe. "
+ "Hence got the full registry.");
getAndStoreFullRegistry();
//乐观锁,版本控制
} else if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)) {
logger.debug("Got delta update with apps hashcode {}", delta.getAppsHashCode());
String reconcileHashCode = "";
//加锁更新数据
if (fetchRegistryUpdateLock.tryLock()) {
try {
updateDelta(delta);
//本地hash码
reconcileHashCode = getReconcileHashCode(applications);
} finally {
fetchRegistryUpdateLock.unlock();
}
} else {
logger.warn("Cannot acquire update lock, aborting getAndUpdateDelta");
}
//比较hash码,如果不一致,全量更新
if (!reconcileHashCode.equals(delta.getAppsHashCode()) || clientConfig.shouldLogDeltaDiff()) {
reconcileAndLogDifference(delta, reconcileHashCode); // this makes a remoteCall
}
} else {
logger.warn("Not updating application delta as another thread is updating it already");
logger.debug("Ignoring delta update with apps hashcode {}, as another thread is updating it already", delta.getAppsHashCode());
}
}
心跳检测线程HeartbeatThread
主要是将自己的信息,appName,id发送到服务器
private class HeartbeatThread implements Runnable {
public void run() {
if (renew()) {
lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
}
}
}
boolean renew() {
EurekaHttpResponse<InstanceInfo> httpResponse;
try {
//发送心跳包,将自己的信息,appName,id发送到服务器
httpResponse = eurekaTransport.registrationClient.sendHeartBeat(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);
logger.debug(PREFIX + "{} - Heartbeat status: {}", appPathIdentifier, httpResponse.getStatusCode());
if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) {
REREGISTER_COUNTER.increment();
logger.info(PREFIX + "{} - Re-registering apps/{}", appPathIdentifier, instanceInfo.getAppName());
long timestamp = instanceInfo.setIsDirtyWithTime();
boolean success = register();
if (success) {
instanceInfo.unsetIsDirty(timestamp);
}
return success;
}
return httpResponse.getStatusCode() == Status.OK.getStatusCode();
} catch (Throwable e) {
logger.error(PREFIX + "{} - was unable to send heartbeat!", appPathIdentifier, e);
return false;
}
}
InstanceInfoReplicator复制器,定时注册自己
public void start(int initialDelayMs) {
//如果是停止状态才启动
if (started.compareAndSet(false, true)) {
//将自己设置成帐数据
instanceInfo.setIsDirty();
//执行自己的run方法,返回Future
Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS);
scheduledPeriodicRef.set(next);
}
}
public void run() {
try {
//刷新服务状态
discoveryClient.refreshInstanceInfo();
//脏时间
Long dirtyTimestamp = instanceInfo.isDirtyWithTime();
if (dirtyTimestamp != null) {
//注册自己
discoveryClient.register();
//清除自己脏数据状态
instanceInfo.unsetIsDirty(dirtyTimestamp);
}
} catch (Throwable t) {
logger.warn("There was a problem with the instance info replicator", t);
} finally {
Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);
scheduledPeriodicRef.set(next);
}
}
小结
- 创建一个EurekaClient同时创建CloudEurekaClient以及父类DiscoveryClient

352

被折叠的 条评论
为什么被折叠?



