所有文章
https://www.cnblogs.com/lay2017/p/11908715.html
正文
eureka服務端維護了一個服務信息的列表,服務端節點之間相互復制服務信息。而作為eureka的客戶端將會從eureka服務端請求這個服務信息列表,選擇對應的實例。本文就來看看eureka服務端對客戶端提供的獲取服務信息列表的http接口。
eureka服務端基於jersey來提供http服務調用,所以我們先找到它的Resource。
ApplicationsResource
@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; }
這里從responseCache當中獲取了Applications的序列號結果直接返回了,所以我們先看看ResponseCache是從哪里來的
可以看到ResponseCache是再ApplicationsResource構造的時候從Registry中獲取的
@Inject ApplicationsResource(EurekaServerContext eurekaServer) { this.serverConfig = eurekaServer.getServerConfig(); this.registry = eurekaServer.getRegistry(); this.responseCache = registry.getResponseCache(); }
我們再看看ResponseCache的get方法做了什么
String get(final Key key, boolean useReadOnlyCache) { Value payload = getValue(key, useReadOnlyCache); if (payload == null || payload.getPayload().equals(EMPTY_PAYLOAD)) { return null; } else { return payload.getPayload(); } }
繼續跟進getValue
Value getValue(final Key key, boolean useReadOnlyCache) { Value payload = null; try { if (useReadOnlyCache) { final Value currentPayload = readOnlyCacheMap.get(key); if (currentPayload != null) { payload = currentPayload; } else { payload = readWriteCacheMap.get(key); readOnlyCacheMap.put(key, payload); } } else { payload = readWriteCacheMap.get(key); } } catch (Throwable t) { logger.error("Cannot get value for key : {}", key, t); } return payload; }
可以看到,其實只是從ReadWriteCacheMap當中獲取對應的值,那么我們再看看ReadWriteCacheMap是怎么被構造的
this.readWriteCacheMap = CacheBuilder.newBuilder().initialCapacity(serverConfig.getInitialCapacityOfResponseCache()) .expireAfterWrite(serverConfig.getResponseCacheAutoExpirationInSeconds(), TimeUnit.SECONDS) .removalListener(new RemovalListener<Key, Value>() { @Override public void onRemoval(RemovalNotification<Key, Value> notification) { Key removedKey = notification.getKey(); if (removedKey.hasRegions()) { Key cloneWithNoRegions = removedKey.cloneWithoutRegions(); regionSpecificKeys.remove(cloneWithNoRegions, removedKey); } } }) .build(new CacheLoader<Key, Value>() { @Override public Value load(Key key) throws Exception { if (key.hasRegions()) { Key cloneWithNoRegions = key.cloneWithoutRegions(); regionSpecificKeys.put(cloneWithNoRegions, key); } Value value = generatePayload(key); return value; } });
從這里可以看出,調用ReadWriteCacheMap的get方法,將會觸發這里的generatePayload方法
我們跟進generatePayload
private Value generatePayload(Key key) { Stopwatch tracer = null; try { String payload; switch (key.getEntityType()) { case Application: boolean isRemoteRegionRequested = key.hasRegions(); // 獲取所有Application if (ALL_APPS.equals(key.getName())) { if (isRemoteRegionRequested) { tracer = serializeAllAppsWithRemoteRegionTimer.start(); payload = getPayLoad(key, registry.getApplicationsFromMultipleRegions(key.getRegions())); } else { tracer = serializeAllAppsTimer.start(); payload = getPayLoad(key, registry.getApplications()); } } else if (ALL_APPS_DELTA.equals(key.getName())) { // ... } else { tracer = serializeOneApptimer.start(); // 獲取某個Application payload = getPayLoad(key, registry.getApplication(key.getName())); } break; // ... } return new Value(payload); } finally { } }
我們看到這里payload主要構成元素是Application,也就是我們需要的服務列表信息。
最后,我們跟進getPayLoad方法,看看這些服務列表信息是怎么被序列號成payload的
private String getPayLoad(Key key, Applications apps) { EncoderWrapper encoderWrapper = serverCodecs.getEncoder(key.getType(), key.getEurekaAccept()); String result; try { result = encoderWrapper.encode(apps); } catch (Exception e) { return ""; } return result; }
編碼器的實現比較多種,這里就不展開了
總結
獲取服務信息列表其實就是從registry當中獲取Applications,然后做一次序列化,最后通過http響應回去。總體來說還是比較簡單的。