EurekaHttpClientDecorator是一个抽象类,存在抽象方法:
protected abstract <R> EurekaHttpResponse<R> execute(RequestExecutor<R> requestExecutor);
@Override
public EurekaHttpResponse<Application> getApplication(final String appName) {
return execute(new RequestExecutor<Application>() {
@Override
public EurekaHttpResponse<Application> execute(EurekaHttpClient delegate) {
return delegate.getApplication(appName);
}
@Override
public RequestType getRequestType() {
return RequestType.GetApplication;
}
});
}
@Override
public EurekaHttpResponse<InstanceInfo> sendHeartBeat(final String appName,
final String id,
final InstanceInfo info,
final InstanceStatus overriddenStatus) {
return execute(new RequestExecutor<InstanceInfo>() {
@Override
public EurekaHttpResponse<InstanceInfo> execute(EurekaHttpClient delegate) {
return delegate.sendHeartBeat(appName, id, info, overriddenStatus);
}
@Override
public RequestType getRequestType() {
return RequestType.SendHeartBeat;
}
});
}
每次调用execute 都是通过 eurekaTransport.queryClient 实现。其中 eurekaTransport.queryClient 为 SessionedEurekaHttpClient。
继承自EurekaHttpClientDecorator的类有如下几个,都在com.netflix.discovery.shared.transport.decorator包里头
入口
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT)
@org.springframework.cloud.context.config.annotation.RefreshScope
@Lazy
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config,
EurekaInstanceConfig instance) {
manager.getInfo(); // force initialization
return new CloudEurekaClient(manager, config, this.optionalArgs,
this.context);
}
...
scheduleServerEndpointTask(eurekaTransport, args);
...
...
if (clientConfig.shouldRegisterWithEureka()) {
EurekaHttpClientFactory newRegistrationClientFactory = null;
EurekaHttpClient newRegistrationClient = null;
try {
// 调用EurekaHttpClients# new EurekaHttpClientFactory()
newRegistrationClientFactory = EurekaHttpClients.registrationClientFactory(
eurekaTransport.bootstrapResolver,
eurekaTransport.transportClientFactory,//jerseyFactory
transportConfig
);
// 调用EurekaHttpClients# new EurekaHttpClientFactory() # EurekaHttpClient#newClient()
newRegistrationClient = newRegistrationClientFactory.newClient();
} catch (Exception e) {
logger.warn("Transport initialization failure", e);
}
eurekaTransport.registrationClientFactory = newRegistrationClientFactory;
eurekaTransport.registrationClient = newRegistrationClient;
}
....
static EurekaHttpClientFactory canonicalClientFactory(final String name,
final EurekaTransportConfig transportConfig,
final ClusterResolver<EurekaEndpoint> clusterResolver,
final TransportClientFactory transportClientFactory) {
return new EurekaHttpClientFactory() {
@Override
public EurekaHttpClient newClient() {
return new SessionedEurekaHttpClient(// 持有 RetryableEurekaHttpClient
name,
RetryableEurekaHttpClient.createFactory(//持有 RedirectingEurekaHttpClient
name,
transportConfig,
clusterResolver,
RedirectingEurekaHttpClient.createFactory(transportClientFactory),
ServerStatusEvaluators.legacyEvaluator()),
transportConfig.getSessionedClientReconnectIntervalSeconds() * 1000
);
}
@Override
public void shutdown() {
wrapClosable(clusterResolver).shutdown();
}
};
}
public SessionedEurekaHttpClient(String name, EurekaHttpClientFactory clientFactory, long sessionDurationMs) {
this.name = name;
this.clientFactory = clientFactory;//RetryableEurekaHttpClient
this.sessionDurationMs = sessionDurationMs;
this.currentSessionDurationMs = randomizeSessionDuration(sessionDurationMs);
Monitors.registerObject(name, this);
}
public static EurekaHttpClientFactory createFactory(final String name,
final EurekaTransportConfig transportConfig,
final ClusterResolver<EurekaEndpoint> clusterResolver,
final TransportClientFactory delegateFactory,
final ServerStatusEvaluator serverStatusEvaluator) {
return new EurekaHttpClientFactory() {
@Override
public EurekaHttpClient newClient() {
return new RetryableEurekaHttpClient(name, transportConfig, clusterResolver, delegateFactory,
serverStatusEvaluator, DEFAULT_NUMBER_OF_RETRIES);
}
@Override
public void shutdown() {
delegateFactory.shutdown();
}
};
}
public static TransportClientFactory createFactory(final TransportClientFactory delegateFactory) {
final DnsServiceImpl dnsService = new DnsServiceImpl();
return new TransportClientFactory() {
@Override
public EurekaHttpClient newClient(EurekaEndpoint endpoint) {
//delegateFactory 就是jerseyFactory
return new RedirectingEurekaHttpClient(endpoint.getServiceUrl(), delegateFactory, dnsService);
}
@Override
public void shutdown() {
delegateFactory.shutdown();
}
};
}
每次调用都是 SessionedEurekaHttpClient 发起。针对调用 getApplication 、sendHeartBeat都是直接调用装饰类EurekaHttpClientDecorator的方法。
// eurekaTransport.registrationClient 是SessionedEurekaHttpClient
eurekaTransport.registrationClient.sendHeartBeat(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);
EurekaHttpClientDecorator#sendHeartBeat
@Override
public EurekaHttpResponse<InstanceInfo> sendHeartBeat(final String appName,
final String id,
final InstanceInfo info,
final InstanceStatus overriddenStatus) {
// 调用装饰类SessionedEurekaHttpClient对应的 execute
return execute(new RequestExecutor<InstanceInfo>() {
@Override
public EurekaHttpResponse<InstanceInfo> execute(EurekaHttpClient delegate) {
return delegate.sendHeartBeat(appName, id, info, overriddenStatus);
}
@Override
public RequestType getRequestType() {
return RequestType.SendHeartBeat;
}
});
}
SessionedEurekaHttpClient#execute
protected <R> EurekaHttpResponse<R> execute(RequestExecutor<R> requestExecutor) {//EurekaHttpClientDecorator
long now = System.currentTimeMillis();
long delay = now - lastReconnectTimeStamp;
if (delay >= currentSessionDurationMs) {
logger.debug("Ending a session and starting anew");
lastReconnectTimeStamp = now;
currentSessionDurationMs = randomizeSessionDuration(sessionDurationMs);
TransportUtils.shutdown(eurekaHttpClientRef.getAndSet(null));
}
//eurekaHttpClient = RetryableEurekaHttpClient
EurekaHttpClient eurekaHttpClient = eurekaHttpClientRef.get();
if (eurekaHttpClient == null) {
// clientFactory.newClient()是 RetryableEurekaHttpClient
eurekaHttpClient = TransportUtils.getOrSetAnotherClient(eurekaHttpClientRef, clientFactory.newClient());
}
//调用EurekaHttpClientDecorator#delegate.sendHeartBeat
//->EurekaHttpClientDecorator#sendHeartBeat->RetryableEurekaHttpClient#execute
return requestExecutor.execute(eurekaHttpClient);
}
RetryableEurekaHttpClient#execute
protected <R> EurekaHttpResponse<R> execute(RequestExecutor<R> requestExecutor) {
List<EurekaEndpoint> candidateHosts = null;
int endpointIdx = 0;
for (int retry = 0; retry < numberOfRetries; retry++) {
EurekaHttpClient currentHttpClient = delegate.get();
EurekaEndpoint currentEndpoint = null;
if (currentHttpClient == null) {
...
currentEndpoint = candidateHosts.get(endpointIdx++);
//clientFactory.newClient = RedirectingEurekaHttpClient
// currentHttpClient 为 RedirectingEurekaHttpClient
currentHttpClient = clientFactory.newClient(currentEndpoint);
}
try {
// requestExecutor 是 EurekaHttpClientDecorator -> EurekaHttpClientDecorator#delegate.sendHeartBeat
// -> EurekaHttpClientDecorator#sendHeartBeat -> EurekaHttpClientDecorator#execute
// -> RedirectingEurekaHttpClient#execute
EurekaHttpResponse<R> response = requestExecutor.execute(currentHttpClient);
if (serverStatusEvaluator.accept(response.getStatusCode(), requestExecutor.getRequestType())) {
delegate.set(currentHttpClient);
if (retry > 0) {
logger.info("Request execution succeeded on retry #{}", retry);
}
return response;
}
} catch (Exception e) {
}
...
}
throw new TransportException("Retry limit reached; giving up on completing the request");
}
RedirectingEurekaHttpClient#execute
@Override
protected <R> EurekaHttpResponse<R> execute(RequestExecutor<R> requestExecutor) {
EurekaHttpClient currentEurekaClient = delegateRef.get();
if (currentEurekaClient == null) {
AtomicReference<EurekaHttpClient> currentEurekaClientRef = new AtomicReference<>(factory.newClient(serviceEndpoint));
try {
EurekaHttpResponse<R> response = executeOnNewServer(requestExecutor, currentEurekaClientRef);
TransportUtils.shutdown(delegateRef.getAndSet(currentEurekaClientRef.get()));
return response;
} catch (Exception e) {
logger.error("Request execution error", e);
TransportUtils.shutdown(currentEurekaClientRef.get());
throw e;
}
} else {
try {
// currentEurekaClient = MetricsCollectingEurekaHttpClient
return requestExecutor.execute(currentEurekaClient);
} catch (Exception e) {
logger.error("Request execution error", e);
delegateRef.compareAndSet(currentEurekaClient, null);
currentEurekaClient.shutdown();
throw e;
}
}
}
private <R> EurekaHttpResponse<R> executeOnNewServer(RequestExecutor<R> requestExecutor,
AtomicReference<EurekaHttpClient> currentHttpClientRef) {
URI targetUrl = null;
for (int followRedirectCount = 0; followRedirectCount < MAX_FOLLOWED_REDIRECTS; followRedirectCount++) {
// requestExecutor = EurekaHttpClientDecorator#delegate.sendHeartBeat
//->EurekaHttpClientDecorator#sendHeartBeat
// currentHttpClientRef = MetricsCollectingEurekaHttpClient
EurekaHttpResponse<R> httpResponse = requestExecutor.execute(currentHttpClientRef.get());
if (httpResponse.getStatusCode() != 302) {
if (followRedirectCount == 0) {
logger.debug("Pinning to endpoint {}", targetUrl);
} else {
logger.info("Pinning to endpoint {}, after {} redirect(s)", targetUrl, followRedirectCount);
}
return httpResponse;
}
targetUrl = getRedirectBaseUri(httpResponse.getLocation());
if (targetUrl == null) {
throw new TransportException("Invalid redirect URL " + httpResponse.getLocation());
}
currentHttpClientRef.getAndSet(null).shutdown();
currentHttpClientRef.set(factory.newClient(new DefaultEndpoint(targetUrl.toString())));
}
String message = "Follow redirect limit crossed for URI " + serviceEndpoint.getServiceUrl();
logger.warn(message);
throw new TransportException(message);
}
MetricsCollectingEurekaHttpClient#execute
@Override
protected <R> EurekaHttpResponse<R> execute(RequestExecutor<R> requestExecutor) {
EurekaHttpClientRequestMetrics requestMetrics = metricsByRequestType.get(requestExecutor.getRequestType());
Stopwatch stopwatch = requestMetrics.latencyTimer.start();
try {
// delegate 就是 JerseyApplicationClient
EurekaHttpResponse<R> httpResponse = requestExecutor.execute(delegate);
requestMetrics.countersByStatus.get(mappedStatus(httpResponse)).increment();
return httpResponse;
} catch (Exception e) {
requestMetrics.connectionErrors.increment();
exceptionsMetric.count(e);
throw e;
} finally {
stopwatch.stop();
}
}