前面章节介绍了 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 服务源码。