註冊流程
如果需要註冊,肯定需要一個註冊的實例端
在EurekaClientAutoConfiguration中尋找EurekaClient
@Bean(destroyMethod = "shutdown")
// @ConditionalOnMissingBean如果spring中沒有該bean則創建,反之不創建
@ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT)
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config) {
return new CloudEurekaClient(manager, config, this.optionalArgs,
this.context);
}
點進去可以看到它是一個接口
public interface EurekaClient extends LookupService
查看它的實現類DiscoveryClient,先是進行一堆初始化賦值,然後創建了三個線程池,最後初始化了所有定時任務
@Inject
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args,
Provider<BackupRegistry> backupRegistryProvider) {
// .. 一些的初始化賦值
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
// ...
} catch (Throwable e) {
throw new RuntimeException("Failed to initialize DiscoveryClient!", e);
}
//...
// 初始化了所有定時任務
initScheduledTasks();
//...
}
繼續追蹤initScheduledTasks()方法,看看心跳檢測初始化時都幹了些什麼
/**
* Initializes all scheduled tasks.
*/
private void initScheduledTasks() {
// ...
// Heartbeat timer
scheduler.schedule(
new TimedSupervisorTask(
"heartbeat",
scheduler,
heartbeatExecutor,
renewalIntervalInSecs,
TimeUnit.SECONDS,
expBackOffBound,
new HeartbeatThread()
),
renewalIntervalInSecs, TimeUnit.SECONDS);
// ...
}
調用了renew()方法,繼續跟蹤看看它做了什麼
/**
* The heartbeat task that renews the lease in the given intervals.
*/
private class HeartbeatThread implements Runnable {
public void run() {
if (renew()) {
lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
}
}
}
InstanceInfo顧名思義,實例信息,先是創建一個實例集合,請求一次服務,如果該服務狀態值是404,則計數器+1並調用註冊方法
/**
* Renew with the eureka service by making the appropriate REST call
*/
boolean renew() {
// 定義一個實例信息集合
EurekaHttpResponse<InstanceInfo> httpResponse;
try {
// 請求服務
httpResponse = eurekaTransport.registrationClient.sendHeartBeat(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);
logger.debug("{} - Heartbeat status: {}", PREFIX + appPathIdentifier, httpResponse.getStatusCode());
if (httpResponse.getStatusCode() == 404) {
// 如果沒有註冊過,則計數器+1
REREGISTER_COUNTER.increment();
logger.info("{} - Re-registering apps/{}", PREFIX + appPathIdentifier, instanceInfo.getAppName());
// 調用註冊方法
return register();
}
return httpResponse.getStatusCode() == 200;
} catch (Throwable e) {
logger.error("{} - was unable to send heartbeat!", PREFIX + appPathIdentifier, e);
return false;
}
}
繼續追蹤register()方法
將實例信息放入了集合中,通過適當的REST調用向eureka進行服務註冊,返回是否成功
/**
* Register with the eureka service by making the appropriate REST call.
*/
boolean register() throws Throwable {
logger.info(PREFIX + appPathIdentifier + ": registering service...");
// 定義一個集合
EurekaHttpResponse<Void> httpResponse;
try {
// 向eureka服務註冊
httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
} catch (Exception e) {
logger.warn("{} - registration failed {}", PREFIX + appPathIdentifier, e.getMessage(), e);
throw e;
}
if (logger.isInfoEnabled()) {
logger.info("{} - registration status: {}", PREFIX + appPathIdentifier, httpResponse.getStatusCode());
}
// 返回操作是否成功
return httpResponse.getStatusCode() == 204;
}
總結
EurekaClient的實現類DiscoveryClient中,DiscoveryClient方法初始化了三個線程池,定時任務的,心跳的,緩存的.
在初始化心時任務中,初始化了心跳檢測的線程,並創建了HeartbeatThread執行了renew()更新方法
通過該方法,請求Eureka服務,如果返回404,則計數器+1,再通過REST調用向eureka服務註冊並返回是否註冊成功.如果不是404,則返回請求是否成功的狀態值.