Spring Cloud 2.2.2 源碼之十二Eureka服務處理獲取服務請求一
大致流程圖
獲取全量服務信息
我們來講下客戶端獲取全量服務信息的時候服務端是怎麼做的。調用的是ApplicationsResource
的getContainers
。主要就是創建一個緩存的Key
對象,對象的屬性值ResponseCacheImpl.ALL_APPS
表示的就是全量,也就是獲取緩存用的,緩存其實是個map
。然後調用responseCache.getGZIP
獲取全量的服務信息。
@GET
public Response getContainers(@PathParam("version") String version,
@HeaderParam(HEADER_ACCEPT) String acceptHeader,
@HeaderParam(HEADER_ACCEPT_ENCODING) String acceptEncoding,
@HeaderParam(EurekaAccept.HTTP_X_EUREKA_ACCEPT) String eurekaAccept,
@Context UriInfo uriInfo,
@Nullable @QueryParam("regions") String regionsStr) {
...
//創建一個緩存對象
Key cacheKey = new Key(Key.EntityType.Application,
ResponseCacheImpl.ALL_APPS,//全量
keyType, CurrentRequestVersion.get(), EurekaAccept.fromString(eurekaAccept), regions
);
Response response;
if (acceptEncoding != null && acceptEncoding.contains(HEADER_GZIP_VALUE)) {
response = Response.ok(responseCache.getGZIP(cacheKey))//獲取壓縮的數據
.header(HEADER_CONTENT_ENCODING, HEADER_GZIP_VALUE)
.header(HEADER_CONTENT_TYPE, returnMediaType)
.build();
} else {
response = Response.ok(responseCache.get(cacheKey))
.build();
}
...
return response;
}
Key緩存的對象
這個對象沒什麼好看的,就是他重寫了hashCode
方法,也就是讓map
可以比對怎麼樣是同一個對象,map
是根據hashCode
相關算法比對的:
可見不同的對象,只要傳入的屬性值相同,那麼hashKey
相同,hashCode()
返回值就相同,在map
中認爲是同一個Key
,就可以獲取同一個對象。
ResponseCacheImpl的getGZIP
把Key
對象傳進去,獲取值,默認是用只讀緩存的,其實內部有三級緩存,只讀,讀寫,註冊表。
getValue獲取值
可以看到,默認先啓用讀緩存readOnlyCacheMap
,如果找到就返回了,否則再看讀寫緩存readWriteCacheMap
,如果寫緩存不存在,就會從註冊表中獲取,這個後面會說這麼做的,存在的話就直接返回,然後都要保存到讀緩存中。這裏爲什麼要這樣設計,讀寫分離,就是爲了提高性能,寫的時候不會影響到讀,讀也不會影響到寫,當然這裏會用定時器來進行數據的同步,但是不是實時的,爲了性能,保證數據最終一致。
這兩個緩存的類型,LoadingCache是谷歌緩存框架裏的,提供了一個方法,就是不存在的時候要怎麼辦,這裏不存在的時候就可以去註冊表中獲取:
readWriteCacheMap不存在的處理方式
如果讀寫緩存不存在,就會去註冊表中獲取,哪裏看出來的呢,創建的時候:
generatePayload
看下面的。
然後直接用JSON
編碼後返回。
registry.getApplications()做了什麼
內部就是獲取了註冊表的所有信息,封裝成Applications
對象:
最後計算出AppsHashCode
後返回:
registry和Applications的結構大致如圖
其實就是做了類型的轉換,好編碼後發到客戶端,數據還是這些數據。
三級緩存基本講完了,首先是讀緩存,然後讀寫緩存,最後註冊表,爲了讀寫分離,後面講他們怎麼進行數據同步的。
好了,今天就到這裏了,希望對學習理解有幫助,大神看見勿噴,僅爲自己的學習理解,能力有限,請多包涵。