前面章节介绍了 DiscoveryClient 类的构造方法,同时也分析了 CacheRefreshThread 刷新任务线程源码。本章节将介绍心跳续约任务线程 HeartbeatThread。源码如下:
/** * The heartbeat task that renews the lease in the given intervals. */ private class HeartbeatThread implements Runnable { public void run() { // 调用 renew() 方法进行续约 if (renew()) { lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis(); } } }
renew() 方法源码如下:
/** * Renew with the eureka service by making the appropriate REST call */ boolean renew() { EurekaHttpResponse<InstanceInfo> httpResponse; try { // 通过 HTTP REST 请求给注册中心发送心跳信息 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; } }
到这里续约源码分析完了。
接下来我们还需要看看 initScheduledTasks() 方法最后的 instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds()) 语句,该语句将当前服务注册到注册中心。instanceInfoReplicator.start() 方法的源码如下:
public void start(int initialDelayMs) { if (started.compareAndSet(false, true)) { instanceInfo.setIsDirty(); // for initial register // 启动一个定时任务,任务指向this,将执行 InstanceInfoReplicator 类下面的 run() 方法 Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS); scheduledPeriodicRef.set(next); } }
上面中 scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS) 将当前类 this 作为执行任务,这是因为该类实现了 Runnable,代码如下:
class InstanceInfoReplicator implements Runnable { //... }
InstanceInfoReplicator 中的 run() 方法源码如下:
public void run() { try { discoveryClient.refreshInstanceInfo(); Long dirtyTimestamp = instanceInfo.isDirtyWithTime(); if (dirtyTimestamp != null) { // 调用 register() 方法实现服务注册 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); } }
到这里 DiscoveryClient 类基本分析完成了,后续章节将介绍 Eureka 服务源码。