摘要: 原創出處 http://www.iocoder.cn/Eureka/eureka-client-init-third/ 「芋道源碼」歡迎轉載,保留摘要,謝謝!
本文主要基於 Eureka 1.8.X 版本
- 1. 概述
- 2. EurekaClient
- 3. DiscoveryClient
1. 概述
本文接《Eureka 源碼解析 —— Eureka-Client 初始化(二)之 EurekaClientConfig》,主要分享 Eureka-Client 自身初始化的過程的第三部分 —— EurekaClient,不包含 Eureka-Client 向 Eureka-Server 的註冊過程( ��後面會另外文章分享 )。
Eureka-Client 自身初始化過程中,涉及到主要對象如下圖:
- 創建 EurekaInstanceConfig對象
- 使用 EurekaInstanceConfig對象 創建 InstanceInfo對象
- 使用 EurekaInstanceConfig對象 + InstanceInfo對象 創建 ApplicationInfoManager對象
- 創建 EurekaClientConfig對象
- 使用 ApplicationInfoManager對象 + EurekaClientConfig對象 創建 EurekaClient對象
考慮到整個初始化的過程中涉及的配置特別多,拆分成三篇文章:
- (一)EurekaInstanceConfig)
- (二)EurekaClientConfig
- 【本文】(三)EurekaClient
下面我們來看看每個類的實現。
推薦 Spring Cloud 書籍:
- 請支持正版。下載盜版,等於主動編寫低級 BUG 。
- 程序猿DD —— 《Spring Cloud微服務實戰》
- 周立 —— 《Spring Cloud與Docker微服務架構實戰》
- 兩書齊買,京東包郵。
2. EurekaClient
com.netflix.discovery.EurekaClient
,Eureka-Client 接口,聲明如下方法:
- 提供多種方法獲取應用集合(
com.netflix.discovery.shared.Applications
) 和 應用實例信息集合(com.netflix.appinfo.InstanceInfo
)。 - 提供方法獲取本地客戶端信息,例如,應用管理器(
com.netflix.appinfo.ApplicationInfoManager
)和 Eureka-Client 配置(com.netflix.discovery.EurekaClientConfig
)。 - 提供方法註冊本地客戶端的健康檢查和 Eureka 事件監聽器。
另外,Eureka 2.X 版本正在開發,該接口爲 Eureka 1.X 和 2.X 提供平滑過渡接口。
This interface does NOT try to clean up the current client interface for eureka 1.x. Rather it tries to provide an easier transition path from eureka 1.x to eureka 2.x.
2.1 LookupService
com.netflix.discovery.shared.LookupService
,查找服務接口,提供簡單單一的方式獲取應用集合(com.netflix.discovery.shared.Applications
) 和 應用實例信息集合( com.netflix.appinfo.InstanceInfo
)。
- 在 Eureka-Client 裏,EurekaClient 繼承該接口。
- 在 Eureka-Server 裏,
com.netflix.eureka.registry.InstanceRegistry
繼承該接口。
3. DiscoveryClient
com.netflix.discovery.DiscoveryClient
,實現 EurekaClient 接口,用於與 Eureka-Server 交互。實現如下方法:
- 向 Eureka-Server 註冊自身服務
- 向 Eureka-Server 續約自身服務
- 向 Eureka-Server 取消自身服務,當關閉時
- 從 Eureka-Server 查詢應用集合和應用實例信息
- 簡單來理解,對 Eureka-Server 服務的增刪改查
3.1 構造方法參數
DiscoveryClient 完整構造方法需要傳入四個參數,實現代碼如下:
|
- ApplicationInfoManager,在《Eureka 源碼解析 —— Eureka-Client 初始化(一)之 EurekaInstanceConfig》有詳細解析。
- EurekaClientConfig,在《Eureka 源碼解析 —— Eureka-Client 初始化(二)之 EurekaClientConfig》有詳細解析。
com.netflix.discovery.BackupRegistry
,備份註冊中心接口。當 Eureka-Client 啓動時,無法從 Eureka-Server 讀取註冊信息(可能掛了),從備份註冊中心讀取註冊信息。實現代碼如下:// BackupRegistry.javapublic interface BackupRegistry {Applications fetchRegistry();Applications fetchRegistry(String[] includeRemoteRegions);}// NotImplementedRegistryImpl.javapublic class NotImplementedRegistryImpl implements BackupRegistry {public Applications fetchRegistry() {return null;}public Applications fetchRegistry(String[] includeRemoteRegions) {return null;}}- 從
com.netflix.discovery.NotImplementedRegistryImpl
可以看出,目前 Eureka-Client 未提供合適的默認實現。
- 從
com.netflix.discovery.AbstractDiscoveryClientOptionalArgs
,DiscoveryClient 可選參數抽象基類。不同於上面三個必填參數,該參數是選填參數,實際生產下使用較少。實現代碼如下:
public abstract class AbstractDiscoveryClientOptionalArgs<T> {/* 生成健康檢查回調的工廠/Provider<HealthCheckCallback> healthCheckCallbackProvider;/生成健康檢查處理器的工廠/Provider<HealthCheckHandler> healthCheckHandlerProvider;/向 Eureka-Server 註冊之前的處理器/PreRegistrationHandler preRegistrationHandler;/Jersey 過濾器集合/Collection<T> additionalFilters;/Jersey 客戶端/EurekaJerseyClient eurekaJerseyClient;/生成 Jersey 客戶端的工廠的工廠/TransportClientFactories transportClientFactories;/** Eureka 事件監聽器集合*/private Set<EurekaEventListener> eventListeners;}com.netflix.appinfo.HealthCheckCallback
,健康檢查回調接口,目前已經廢棄,使用 HealthCheckHandler 替代,你可以不關注該參數。com.netflix.appinfo.HealthCheckHandler
,健康檢查處理器接口,目前暫未提供合適的默認實現,唯一提供的com.netflix.appinfo.HealthCheckCallbackToHandlerBridge
,用於將 HealthCheckCallback 橋接成 HealthCheckHandler,實現代碼如下:// HealthCheckHandler.javapublic interface HealthCheckHandler {InstanceInfo.InstanceStatus getStatus(InstanceInfo.InstanceStatus currentStatus);}// HealthCheckCallbackToHandlerBridge.javapublic class HealthCheckCallbackToHandlerBridge implements HealthCheckHandler {private final HealthCheckCallback callback;public HealthCheckCallbackToHandlerBridge() {callback = null;}public HealthCheckCallbackToHandlerBridge(HealthCheckCallback callback) {this.callback = callback;}public InstanceInfo.InstanceStatus getStatus(InstanceInfo.InstanceStatus currentStatus) {if (null == callback || InstanceInfo.InstanceStatus.STARTING == currentStatus|| InstanceInfo.InstanceStatus.OUT_OF_SERVICE == currentStatus) { // Do not go to healthcheck handler if the status is starting or OOS.return currentStatus;}return callback.isHealthy() ? InstanceInfo.InstanceStatus.UP : InstanceInfo.InstanceStatus.DOWN;}}- 在 Spring-Cloud-Eureka-Client,提供了默認實現
org.springframework.cloud.netflix.eureka.EurekaHealthCheckHandler
,需要結合spirng-boot-actuate
使用,感興趣的同學可以看看。本文暫不拓展開,後面另開文章分享。(TODO[0004]:健康檢查)
- 在 Spring-Cloud-Eureka-Client,提供了默認實現
com.netflix.discovery.PreRegistrationHandler
,向 Eureka-Server 註冊之前的處理器接口,目前暫未提供默認實現。通過實現該接口,可以在註冊前做一些自定義的處理。實現代碼如下:
public interface PreRegistrationHandler {void beforeRegistration();}- x
additionalFilters
,Jersey 過濾器集合。這裏聲明泛型<T>
的原因,Jersey 1.X 和 Jersey 2.X 的過濾器接口不同,通過泛型來支持。實現代碼如下:// Jersey1DiscoveryClientOptionalArgs.javapublic class Jersey1DiscoveryClientOptionalArgs extends AbstractDiscoveryClientOptionalArgs<ClientFilter> {}// Jersey2DiscoveryClientOptionalArgs.javapublic class Jersey2DiscoveryClientOptionalArgs extends AbstractDiscoveryClientOptionalArgs<ClientRequestFilter> {}// DiscoveryClientOptionalArgs.javapublic static class DiscoveryClientOptionalArgs extends Jersey1DiscoveryClientOptionalArgs {}- Jersey 1.X 使用 ClientFilter 。ClientFilter 目前有兩個過濾器實現:EurekaIdentityHeaderFilter 、DynamicGZIPContentEncodingFilter 。
- Jersey 2.X 使用 ClientRequestFilter 。
- DiscoveryClient 使用 DiscoveryClientOptionalArgs,即 Jersey 1.X 。
eurekaJerseyClient
,Jersey 客戶端。該參數目前廢棄,使用下面 TransportClientFactories 參數來進行生成。com.netflix.discovery.shared.transport.jersey.TransportClientFactories
,生成 Jersey 客戶端工廠的工廠接口。目前有 Jersey1TransportClientFactories 、Jersey2TransportClientFactories 兩個實現。TransportClientFactories 實現代碼如下:// TransportClientFactories.javapublic interface TransportClientFactories<F> {TransportClientFactory newTransportClientFactory(final Collection<F> additionalFilters,final EurekaJerseyClient providedJerseyClient);TransportClientFactory newTransportClientFactory(final EurekaClientConfig clientConfig,final Collection<F> additionalFilters,final InstanceInfo myInstanceInfo);}// TransportClientFactory.javapublic interface TransportClientFactory {EurekaHttpClient newClient(EurekaEndpoint serviceUrl);void shutdown();}- 第一個方法已經廢棄,這就是爲什麼說上面的
eurekaJerseyClient
參數( 不是 EurekaJerseyClient 類)已經廢棄,被第二個方法取代。相比來說,第二個方法對 EurekaJerseyClient 創建封裝會更好。
- 第一個方法已經廢棄,這就是爲什麼說上面的
com.netflix.discovery.EurekaEventListener
,Eureka 事件監聽器。實現代碼如下:
// EurekaEventListener.javapublic interface EurekaEventListener {}// EurekaEvent.javapublic interface EurekaEvent {}// DiscoveryEvent.javapublic abstract class DiscoveryEvent implements EurekaEvent {private final long timestamp;}com.netflix.discovery.StatusChangeEvent
,應用實例狀態變更事件,在《Eureka 源碼解析 —— 應用實例註冊發現 (一)之註冊》「2.1 應用實例信息複製器」 有詳細解析。com.netflix.discovery.CacheRefreshedEvent
,在《Eureka 源碼解析 —— 應用實例註冊發現 (六)之全量獲取》「2.4 發起獲取註冊信息」 有詳細解析。
3.2 構造方法
DiscoveryClient 的構造方法實現代碼相對較多,已經將代碼切塊 + 中文註冊,點擊 DiscoveryClient 鏈接,對照下面每個小結閱讀理解。
3.2.1 賦值 AbstractDiscoveryClientOptionalArgs
|
3.2.2 賦值 ApplicationInfoManager、EurekaClientConfig
|
3.2.3 賦值 BackupRegistry
|
3.2.4 初始化 InstanceInfoBasedUrlRandomizer
TODO[0016]:InstanceInfoBasedUrlRandomizer
|
3.2.5 初始化 Applications 在本地的緩存
|
- 在創建 DiscoveryClient 時,
localRegionApps
爲空。 - 定時任務間隔從 Eureka-Server 拉取註冊應用信息到本地緩存,在 《Eureka 源碼解析 —— 應用實例註冊發現 (六)之全量獲取》 有詳細解析。
3.2.6 獲取哪些 Region 集合的註冊信息
|
3.2.7 初始化拉取、心跳的監控
|
- 每次成功向 Eureka-Serve 心跳或者從從 Eureka-Server 拉取註冊信息後,都會更新相應時間戳。
- 配合 Netflix Servo 實現監控信息採集。
- 對
com.netflix.discovery.util.ThresholdLevelsMetric
感興趣的同學可以點擊鏈接查看。本文暫不拓展開,後面另開文章分享。(TODO[0012]:監控相關)
3.2.8 結束初始化,當無需和 Eureka-Server 交互
|
3.2.9 初始化線程池
|
scheduler
,定時任務線程池,初始化大小爲 2,一個給heartbeatExecutor
,一個給cacheRefreshExecutor
。heartbeatExecutor
、cacheRefreshExecutor
在提交給scheduler
才聲明具體的任務。
3.2.10 初始化 Eureka 網絡通信相關
|
- 本文暫不拓展開,在 《Eureka 源碼解析 —— EndPoint 與 解析器》 和 《Eureka 源碼解析 —— 網絡通信》 詳細解析。
3.2.11 初始化 InstanceRegionChecker
|
com.netflix.discovery.AzToRegionMapper
,主要用於亞馬遜 AWS,跳過。com.netflix.discovery.InstanceRegionChecker
,應用實例信息區域(region
)校驗,實現代碼如下:public class InstanceRegionChecker {// ... 省略和亞馬遜 AWS 相關的屬性和方法/*** 本地區域( Region )*/private final String localRegion;public boolean isLocalRegion(@Nullable String instanceRegion) {return null == instanceRegion || instanceRegion.equals(localRegion); // no region == local}public String getLocalRegion() {return localRegion;}}
3.2.12 從 Eureka-Server 拉取註冊信息
|
- 調用
#fetchRegistry(false)
方法,從 Eureka-Server 初始拉取註冊信息。在(TO後文鏈接)詳細解析。 調用
#fetchRegistryFromBackup()
方法,若初始拉取註冊信息失敗,從備份註冊中心獲取。實現代碼如下:// DiscoveryClient.javaprivate void fetchRegistryFromBackup() {try {"deprecation")(BackupRegistry backupRegistryInstance = newBackupRegistryInstance();if (null == backupRegistryInstance) { // backward compatibility with the old protected method, in case it is being used.backupRegistryInstance = backupRegistryProvider.get();}if (null != backupRegistryInstance) {Applications apps = null;if (isFetchingRemoteRegionRegistries()) {String remoteRegionsStr = remoteRegionsToFetch.get();if (null != remoteRegionsStr) {apps = backupRegistryInstance.fetchRegistry(remoteRegionsStr.split(","));}} else {apps = backupRegistryInstance.fetchRegistry();}if (apps != null) {final Applications applications = this.filterAndShuffle(apps);applications.setAppsHashCode(applications.getReconcileHashCode());localRegionApps.set(applications);logTotalInstances();logger.info("Fetched registry successfully from the backup");}} else {logger.warn("No backup registry instance defined & unable to find any discovery servers.");}} catch (Throwable e) {logger.warn("Cannot fetch applications from apps although backup registry was specified", e);}}- BackupRegistry 目前暫未提供默認實現,需要自行相關邏輯。
3.2.13 執行向 Eureka-Server 註冊之前的處理器
|
3.2.14 初始化定時任務
|
- 初始化從 Eureka-Server 拉取註冊信息執行器,在 《Eureka 源碼解析 —— 應用實例註冊發現 (六)之全量獲取》 詳細解析。
- 初始化向 Eureka-Server 心跳(續租)執行器,在 《Eureka 源碼解析 —— 應用實例註冊發現(二)之續租》 詳細解析。
3.2.15 向 Servo 註冊監控
|
- 配合 Netflix Servo 實現監控信息採集。
3.2.16 初始化完成
|