【Spring Cloud】Eureka-Client 源碼解讀
一、前言
看源碼:抓大放小,先主流程,再細(xì)枝末節(jié)。
用技巧連蒙帶猜:
看方法名(英文名)
看注釋
搭建環(huán)境:
// 定位:eureka-examples 模塊下
// 修改 ExampleEurekaClient.java
// 1. 增加一個(gè)方法,用于初始化環(huán)境變量,方便調(diào)試
private static void injectEurekaConfiguration() throws UnknownHostException {
String myHostName = InetAddress.getLocalHost().getHostName();
String myServiceUrl = "http://" + myHostName + ":8080/v2/";
System.setProperty("eureka.region", "default");
System.setProperty("eureka.name", "eureka");
System.setProperty("eureka.vipAddress", "eureka.mydomain.net");
System.setProperty("eureka.port", "8080");
System.setProperty("eureka.preferSameZone", "false");
System.setProperty("eureka.shouldUseDns", "false");
System.setProperty("eureka.shouldFetchRegistry", "false");
System.setProperty("eureka.serviceUrl.defaultZone", myServiceUrl);
System.setProperty("eureka.serviceUrl.default.defaultZone", myServiceUrl);
System.setProperty("eureka.awsAccessId", "fake_aws_access_id");
System.setProperty("eureka.awsSecretKey", "fake_aws_secret_key");
System.setProperty("eureka.numberRegistrySyncRetries", "0");
}
// 2. 在 main 方法添加
public static void main(String[] args) throws UnknownHostException {
// 添加如下這行
injectEurekaConfiguration();
... ...
}
復(fù)制代碼二、從源碼中學(xué)到了什么
三、直接懟源碼
(1)eureka-client 如何啟動(dòng)(初始化)?
代碼如下:
// 定位:com.netflix.eureka.ExampleEurekaClient.java
public static void main(String[] args) throws UnknownHostException {
// 1. 初始化 eureka 環(huán)境變量
injectEurekaConfiguration();
// 2. 創(chuàng)建 eureka 服務(wù)
ExampleEurekaClient sampleClient = new ExampleEurekaClient();
// 3. 創(chuàng)建服務(wù)實(shí)例管理器
ApplicationInfoManager applicationInfoManager =
initializeApplicationInfoManager(new MyDataCenterInstanceConfig());
// 4. 創(chuàng)建 eureka-client
EurekaClient client =
initializeEurekaClient(applicationInfoManager, new DefaultEurekaClientConfig());
... ...
}
復(fù)制代碼過(guò)程如下:
初始化
eureka環(huán)境變量創(chuàng)建
eureka服務(wù),會(huì)有一個(gè)eureka-client創(chuàng)建服務(wù)實(shí)例管理器
ApplicationInfoManager applicationInfoManager = initializeApplicationInfoManager(new MyDataCenterInstanceConfig());
復(fù)制代碼構(gòu)建服務(wù)實(shí)例(
InstanceInfo)構(gòu)建服務(wù)實(shí)例管理器(
ApplicationInfoManager)創(chuàng)建
eureka-client(通過(guò)構(gòu)造DiscoveryClient)處理配置
服務(wù)的注冊(cè)和注冊(cè)表的抓取(初始化網(wǎng)絡(luò)通信組件)
創(chuàng)建幾個(gè)線(xiàn)程池,啟動(dòng)調(diào)度任務(wù)
注冊(cè)監(jiān)控項(xiàng)
(2)eureka-client 如何服務(wù)注冊(cè)的?
針對(duì)注冊(cè),提出問(wèn)題:
什么時(shí)候進(jìn)行服務(wù)注冊(cè)?初始化
eureka-client時(shí)候
eureka-client的服務(wù)注冊(cè),是在InstanceInfoReplicator中完成的。
服務(wù)注冊(cè)做哪些操作?主要發(fā)送
HTTP請(qǐng)求
針對(duì)這個(gè)兩個(gè)問(wèn)題,來(lái)看下源碼。雖然這部分的源碼寫(xiě)的不好,但也可以學(xué)習(xí)了解下他人的思路。
這部分源碼比較難找,實(shí)際是在創(chuàng)建 DiscoveryClient 的 initScheduledTasks()(初始化調(diào)度任務(wù))
// 定位:com.netflix.discovery.DiscoveryClient.java
private void initScheduledTasks() {
// InstanceRegisterManager:實(shí)例注冊(cè)管理器,專(zhuān)門(mén)來(lái)管理實(shí)例注冊(cè)
// 傳參:默認(rèn) 40秒
instanceInfoReplicator.start(...);
}
復(fù)制代碼啟動(dòng)實(shí)例注冊(cè)管理器(
InstanceRegisterManager)
// 定位:com.netflix.discovery.InstanceInfoReplicator.java
public void start(int initialDelayMs) {
// 原子操作
if (started.compareAndSet(false, true)) {
// 1. 先設(shè)置 isDirty = true
instanceInfo.setIsDirty();
// 2. 調(diào)度器執(zhí)行,將自身傳入,并且調(diào)度時(shí)間默認(rèn)為 40 秒
// 所以會(huì)執(zhí)行 InstanceInfoReplicator.run() 方法
Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS);
scheduledPeriodicRef.set(next);
}
}
復(fù)制代碼執(zhí)行
InstanceInfoReplicator.run()
// 定位:com.netflix.discovery.InstanceInfoReplicator.java
// 會(huì)發(fā)現(xiàn):class InstanceInfoReplicator implements Runnable,是可創(chuàng)建線(xiàn)程的。
public void run() {
try {
// 1. 刷新了服務(wù)實(shí)例的信息,拿到服務(wù)的狀態(tài)
discoveryClient.refreshInstanceInfo();
Long dirtyTimestamp = instanceInfo.isDirtyWithTime();
if (dirtyTimestamp != null) {
// 2. 注冊(cè):因?yàn)橹耙呀?jīng)設(shè)置 isDirty = true,所以下面直接注冊(cè)
discoveryClient.register();
// 3. 設(shè)置 isDirty = false
instanceInfo.unsetIsDirty(dirtyTimestamp);
}
} catch (Throwable t) {
logger.warn("There was a problem with the instance info replicator", t);
} finally {
// 4. 再次把自己丟進(jìn)調(diào)度線(xiàn)程中
Future next =
scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);
scheduledPeriodicRef.set(next);
}
}
復(fù)制代碼重要:注冊(cè)
discoveryClient.register();
// 定位:com.netflix.discovery.DiscoveryClient.java
boolean register() throws Throwable {
EurekaHttpResponse<Void> httpResponse;
try {
// 發(fā)送 HTTP 請(qǐng)求
httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
... ...
}
... ...
return httpResponse.getStatusCode() == 204;
}
作者:卷卷啊
鏈接:https://juejin.cn/post/6968080788868825118
來(lái)源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
