Spring Cloud 2.2.2 源码之五Eureka客户端注册服务
服务注册和续约的大致流程
先说下服务注册吧,毕竟作为一个提供服务的客户端,注册到注册中心去比较重要,也是第一步。
InstanceInfoReplicator的run
这个就是注册服务的调度方法,首次延迟30
秒执行,后面可能会调整。所以严格说他不是一个定时的任务,只是可调节的定时的调度任务。首先进行客户端实例信息刷新,然后看是否有状态改变,有贵爱彼岸的话dirtyTimestamp
不为空,有改变就要通知注册中心,所以要去注册,完成之后继续调度任务。
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);
}
}
DiscoveryClient的refreshInstanceInfo
这里主要的是刷新状态信息,根据HealthCheckHandler
去获取当前实例的状态信息,然后进行设置。
void refreshInstanceInfo() {
applicationInfoManager.refreshDataCenterInfoIfRequired();//刷新数据中心,和AWS亚马逊云有关
applicationInfoManager.refreshLeaseInfoIfRequired();//更新租约信息
InstanceStatus status;
try {//获取实例状态
status = getHealthCheckHandler().getStatus(instanceInfo.getStatus());
} catch (Exception e) {
logger.warn("Exception from healthcheckHandler.getStatus, setting status to DOWN", e);
status = InstanceStatus.DOWN;
}
if (null != status) {
applicationInfoManager.setInstanceStatus(status);
}
}
ApplicationInfoManager的setInstanceStatus
主要是这里,首先获取新的状态,然后设置到实例中,内部会有判断,如果是新的就设置标记,返回先前的状态,如果有改变就要进行通知。
public synchronized void setInstanceStatus(InstanceStatus status) {
InstanceStatus next = instanceStatusMapper.map(status);//获取下一个新状态
if (next == null) {
return;
}
//如果状态有改变,会返回先前状态,否则就是null
InstanceStatus prev = instanceInfo.setStatus(next);
if (prev != null) {//有改变了才广播
for (StatusChangeListener listener : listeners.values()) {
try {
listener.notify(new StatusChangeEvent(prev, next));
} catch (Exception e) {
logger.warn("failed to notify listener: {}", listener.getId(), e);
}
}
}
}
InstanceInfo的setStatus
设置信息,如果是新的就设置更新标记,isInstanceInfoDirty=true
,返回先前的状态。
public synchronized InstanceStatus setStatus(InstanceStatus status) {
if (this.status != status) {
InstanceStatus prev = this.status;
this.status = status;
setIsDirty();//设置状态更新
return prev;
}
return null;
}
public synchronized void setIsDirty() {
isInstanceInfoDirty = true;
lastDirtyTimestamp = System.currentTimeMillis();
}
DiscoveryClient的状态改变事件监听
前面忘记说了DiscoveryClient
初始化的时候还创建了一个监听器,监听实例状态改变,如果有改变不为DOWN
的话,就会调用instanceInfoReplicator.onDemandUpdate();
:
InstanceInfoReplicator的onDemandUpdate
其实这个就是又提交了一个服务注册的任务,里面还是调用InstanceInfoReplicator
的run
,把前一个任务取消掉,因为这个scheduler
只有一个线程核心线程在执行任务队列的任务,所以前一个任务被取消了,不会循环调度,就只有一个新提交的任务会循环调度。
public boolean onDemandUpdate() {
if (rateLimiter.acquire(burstSize, allowedRatePerMinute)) {//满足频率
if (!scheduler.isShutdown()) {
scheduler.submit(new Runnable() {//提交新任务
@Override
public void run() {
logger.debug("Executing on-demand update of local InstanceInfo");
Future latestPeriodic = scheduledPeriodicRef.get();//获取最近的一次任务
if (latestPeriodic != null && !latestPeriodic.isDone()) {//如果没完成
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;
}
}
DiscoveryClient的register
任务执行到这里的时候,会发现dirtyTimestamp不为空了,因为状态被改过了,所以可以进行想注册中心注册了。
isInstanceInfoDirty
已经是true
了。
public synchronized Long isDirtyWithTime() {
if (isInstanceInfoDirty) {
return lastDirtyTimestamp;
} else {
return null;
}
}
内部最后就是JerseyApplicationClient
的post
方法。
注册完了再清楚状态,继续调度。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。