本文主要研究下netflix的EurekaHttpClient

EurekaHttpClient

eureka-client-1.8.8-sources.jar!/com/netflix/discovery/shared/transport/EurekaHttpClient.java

public interface EurekaHttpClient {

    EurekaHttpResponse<Void> register(InstanceInfo info);

    EurekaHttpResponse<Void> cancel(String appName, String id);

    EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id, InstanceInfo info, InstanceStatus overriddenStatus);

    EurekaHttpResponse<Void> statusUpdate(String appName, String id, InstanceStatus newStatus, InstanceInfo info);

    EurekaHttpResponse<Void> deleteStatusOverride(String appName, String id, InstanceInfo info);

    EurekaHttpResponse<Applications> getApplications(String... regions);

    EurekaHttpResponse<Applications> getDelta(String... regions);

    EurekaHttpResponse<Applications> getVip(String vipAddress, String... regions);

    EurekaHttpResponse<Applications> getSecureVip(String secureVipAddress, String... regions);

    EurekaHttpResponse<Application> getApplication(String appName);

    EurekaHttpResponse<InstanceInfo> getInstance(String appName, String id);

    EurekaHttpResponse<InstanceInfo> getInstance(String id);

    void shutdown();
}
可以看到这个client接口定义了eureka server的一些low level rest api,其中包括register、cancel、sendHeartBeat、statusUpdate、getApplications等。

EurekaHttpClientDecorator

eureka-client-1.8.8-sources.jar!/com/netflix/discovery/shared/transport/decorator/EurekaHttpClientDecorator.java

public abstract class EurekaHttpClientDecorator implements EurekaHttpClient {

    public enum RequestType {
        Register,
        Cancel,
        SendHeartBeat,
        StatusUpdate,
        DeleteStatusOverride,
        GetApplications,
        GetDelta,
        GetVip,
        GetSecureVip,
        GetApplication,
        GetInstance,
        GetApplicationInstance
    }

    public interface RequestExecutor<R> {
        EurekaHttpResponse<R> execute(EurekaHttpClient delegate);

        RequestType getRequestType();
    }

    protected abstract <R> EurekaHttpResponse<R> execute(RequestExecutor<R> requestExecutor);

    //......
}
EurekaHttpClientDecorator通过定义一个抽象方法execute(RequestExecutor<R> requestExecutor),来包装EurekaHttpClient

EurekaHttpClientDecorator的子类

继承自EurekaHttpClientDecorator的类有如下几个,都在com.netflix.discovery.shared.transport.decorator包里头
  • MetricsCollectingEurekaHttpClient
  • RedirectingEurekaHttpClient
  • RetryableEurekaHttpClient
  • SessionedEurekaHttpClient

EurekaHttpClientFactory(top level)

eureka-client-1.8.8-sources.jar!/com/netflix/discovery/shared/transport/EurekaHttpClientFactory.java

/**
 * A top level factory to create http clients for application/eurekaClient use
 *
 * @author Tomasz Bak
 */
public interface EurekaHttpClientFactory {

    EurekaHttpClient newClient();

    void shutdown();

}
这个是EurekaHttpClient的工厂高级别接口,定义了newClient()以及shutdown()方法

EurekaHttpClientFactory的实现类

  • RetryableEurekaHttpClient

eureka-client-1.8.8-sources.jar!/com/netflix/discovery/shared/transport/decorator/RetryableEurekaHttpClient.java

    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();
            }
        };
    }
创建的是经过RetryableEurekaHttpClient包装的client
  • MetricsCollectingEurekaHttpClient

eureka-client-1.8.8-sources.jar!/com/netflix/discovery/shared/transport/decorator/MetricsCollectingEurekaHttpClient.java

    public static EurekaHttpClientFactory createFactory(final EurekaHttpClientFactory delegateFactory) {
        final Map<RequestType, EurekaHttpClientRequestMetrics> metricsByRequestType = initializeMetrics();
        final ExceptionsMetric exceptionMetrics = new ExceptionsMetric(EurekaClientNames.METRIC_TRANSPORT_PREFIX + "exceptions");
        return new EurekaHttpClientFactory() {
            @Override
            public EurekaHttpClient newClient() {
                return new MetricsCollectingEurekaHttpClient(
                        delegateFactory.newClient(),
                        metricsByRequestType,
                        exceptionMetrics,
                        false
                );
            }

            @Override
            public void shutdown() {
                shutdownMetrics(metricsByRequestType);
                exceptionMetrics.shutdown();
            }
        };
    }
创建的是经过MetricsCollectingEurekaHttpClient包装的client
  • EurekaHttpClients

eureka-client-1.8.8-sources.jar!/com/netflix/discovery/shared/transport/EurekaHttpClients.java

    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(
                        name,
                        RetryableEurekaHttpClient.createFactory(
                                name,
                                transportConfig,
                                clusterResolver,
                                RedirectingEurekaHttpClient.createFactory(transportClientFactory),
                                ServerStatusEvaluators.legacyEvaluator()),
                        transportConfig.getSessionedClientReconnectIntervalSeconds() * 1000
                );
            }

            @Override
            public void shutdown() {
                wrapClosable(clusterResolver).shutdown();
            }
        };
    }
创建的是经过RedirectingEurekaHttpClient、RetryableEurekaHttpClient、SessionedEurekaHttpClient包装之后的client
而原始的EurekaHttpClient则通过TransportClientFactory创建

TransportClientFactory(low level)

eureka-client-1.8.8-sources.jar!/com/netflix/discovery/shared/transport/TransportClientFactory.java

/**
 * A low level client factory interface. Not advised to be used by top level consumers.
 *
 * @author David Liu
 */
public interface TransportClientFactory {

    EurekaHttpClient newClient(EurekaEndpoint serviceUrl);

    void shutdown();

}
如注释上所说,不建议高级别的消费者使用,是一个低级别的api

TransportClientFactory实现类

  • JerseyEurekaHttpClientFactory

eureka-client-1.8.8-sources.jar!/com/netflix/discovery/shared/transport/jersey/JerseyEurekaHttpClientFactory.java

  • JerseyRemoteRegionClientFactory

eureka-core-1.8.8-sources.jar!/com/netflix/eureka/transport/JerseyRemoteRegionClientFactory.java

  • RestTemplateTransportClientFactory

spring-cloud-netflix-eureka-client-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/eureka/http/RestTemplateTransportClientFactory.java

上面这三个是有专门的类实现,下面这几个是匿名类实现

  • RedirectingEurekaHttpClient
  • EurekaServerHttpClients
  • Jersey1TransportClientFactories
  • MetricsCollectingEurekaHttpClient

小结

netflix的eureka关于httpClient的接口为EurekaHttpClient,其工厂方法主要分类top level的EurekaHttpClientFactory以及low level的TransportClientFactory。

  • top level的话,主要是通过decorator模式进行一系列包装,像EurekaHttpClients创建的则是经过RedirectingEurekaHttpClient、RetryableEurekaHttpClient、SessionedEurekaHttpClient包装的client。
  • low levle的话,主要是底层的http远程调用的实现,netflix提供的是基于Jersey的版本,而spring cloud则提供了基于RestTemplate的版本。

doc


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...