Eureka源码—EurekaClient

前言

本篇文章主要解读Eureka-Client初始化的相关源码,文章较长,请谨慎点击!

EurekaInstanceConfig

MyDataCenterInstanceConfig类结构图

EurekaInstanceConfig简介

所属包:com.netflix.appinfo.EurekaInstanceConfigEureka 应用实例配置接口(Application Provider,Application Consumer)。

EurekaInstanceConfig源码

博主已添加中文注释,点击查看

EurekaInstanceConfig重要属性或者重要方法

  • getInstanceId()获取实例id,组成结构为${spring.application.name}:${spring.application.instance_id:${random.value}}默认为null。
  • geAppName()获取应用名,默认为”unknown”。
  • getLeaseRenewalIntervalInSeconds()获取租约续约频率,单位为秒。默认为30s。应用发送心跳给Eureka-Server进行续约(告诉Eureka-Server自己还活着)。

  • getLeaseExpirationDurationInSeconds() 获取租约过期时间,单位为秒。默认为90s。如果超过该时间,应用还没有向Eureka-Server发送心跳,那该租约就过期了,Eureka-Serever会进行应用移除。

  • getMetadataMap()获取实例的元数据。如果你想自定义一些数据,在各服务之间使用,就需要该方法。

  • getHealthCheckUrlPath(),getHealthCheckUrl(),getSecureHealthCheckUrl()健康检查相关的几个方法。

  • getNamespace()获取命名空间,已配置对应的eureka属性,默认为eureka

AbstractInstanceConfig

AbstractInstanceConfig简介

所属包:com.netflix.appinfo.AbstractInstanceConfigEureka 应用实例配置抽象基类,主要实现一些相对通用的配置

AbstractInstanceConfig源码

博主已添加中文注释,点击查看

AbstractInstanceConfig重要属性或者重要方法

  • 主要设置一些基础的属性,以及对应的get/set方法
  • getHostInfo()获取本地服务器的主机名和主机IP地址

PropertiesInstanceConfig

PropertiesInstanceConfig简介

所属包:com.netflix.appinfo.PropertiesInstanceConfig通过配置文件进行Eureka实例配置的抽象基类

PropertiesInstanceConfig源码

博主已添加中文注释,点击查看

PropertiesInstanceConfig重要属性或者重要方法

  • namespace命名空间。

  • configInstance配置文件,基于Netflix Archaius 1.x 实现读取配置文件。基于Netflix Archaius 2.x 的还在开发中。

  • appGrpNameFromEnv从环境变量中获取应用分组,ConfigurationManager.getConfigInstance获取当前的系统范围配置。

  • Archaius1Utils.initConfig(CommonConstants.CONFIG_FILE_NAME)CommonConstants.CONFIG_FILE_NAMEeureka-clientArchaius1Utils.initConfig方法源码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    public final class Archaius1Utils {

    private static final Logger logger = LoggerFactory.getLogger(Archaius1Utils.class);

    private static final String ARCHAIUS_DEPLOYMENT_ENVIRONMENT = "archaius.deployment.environment";
    private static final String EUREKA_ENVIRONMENT = "eureka.environment";

    public static DynamicPropertyFactory initConfig(String configName) {

    // 配置文件对象
    DynamicPropertyFactory configInstance = DynamicPropertyFactory.getInstance();
    // 配置文件名,如果configName没有配置,即为CommonConstants.CONFIG_FILE_NAME("eureka-client")
    DynamicStringProperty EUREKA_PROPS_FILE = configInstance.getStringProperty("eureka.client.props", configName);

    // 配置文件环境
    String env = ConfigurationManager.getConfigInstance().getString(EUREKA_ENVIRONMENT, "test");
    // 将配置文件加载到环境变量
    ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, env);

    String eurekaPropsFile = EUREKA_PROPS_FILE.get();
    try {
    //读取配置文件到环境变量,首先读取 ${eureka.client.props} 对应的配置文件;然后读取 ${eureka.client.props}-${eureka.environment} 对应的配置文件。若有相同属性,进行覆盖。
    ConfigurationManager.loadCascadedPropertiesFromResources(eurekaPropsFile);
    } catch (IOException e) {
    logger.warn(
    "Cannot find the properties specified : {}. This may be okay if there are other environment "
    + "specific properties or the configuration is installed with a different mechanism.",
    eurekaPropsFile);

    }

    return configInstance;
    }
    }
  • 其他实现方法基本类似,都是从配置文件中获取值,举一个例子:

    isInstanceEnabledOnit():从配置文件中获取是否在实例初始化的时候开启,并传一个默认值(这里是父类AbstractInstanceConfig中实现的方法),namespace的属性key都在PropertyBasedInstanceConfigConstants中

MyDataCenterInstanceConfig

MyDataCenterInstanceConfig简介

所属包:com.netflix.appinfo.MyDataCenterInstanceConfigEureka应用实例配置实现类

MyDataCenterInstanceConfig源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MyDataCenterInstanceConfig extends PropertiesInstanceConfig implements EurekaInstanceConfig {
/**
* 无参构造方法
*/
public MyDataCenterInstanceConfig() {
}

public MyDataCenterInstanceConfig(String namespace) {
//调用父类含有namespace参数的构造函数进行初始化
super(namespace);
}

public MyDataCenterInstanceConfig(String namespace, DataCenterInfo dataCenterInfo) {
//调用父类含有namespace和dataCenterInfo参数的构造函数进行初始化
super(namespace, dataCenterInfo);
}

}

InstanceInfo

InstanceInfo简介

所属包:com.netflix.appinfo.InstanceInfo应用实例信息。Eureka-Client 向 Eureka-Server 注册该对象信息。注册成功后,可以被其他 Eureka-Client 发现。Eureka通过com.netflix.appinfo.providers.EurekaConfigBasedInstanceInfoProvider基于EurekaInstanceConfig创建InstanceInfo

EurekaConfigBasedInstanceInfoProvider源码

博主已添加中文注释,点击查看

EurekaConfigBasedInstanceInfoProvider重要属性或者重要方法

  • 基本上每个属性和每个方法都添加了注释

  • 其中vip地址解析器源码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public interface VipAddressResolver {

    /**
    * Convert <code>VIPAddress</code> by substituting environment variables if necessary.
    *
    * @param vipAddressMacro the macro for which the interpolation needs to be made.
    * @return a string representing the final <code>VIPAddress</code> after substitution.
    */
    String resolveDeploymentContextBasedVipAddresses(String vipAddressMacro);
    }

    实现类源码(Archaius1实现,Archaius2还在开发中):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    public class Archaius1VipAddressResolver implements VipAddressResolver {

    private static final Logger logger = LoggerFactory.getLogger(Archaius1VipAddressResolver.class);

    private static final Pattern VIP_ATTRIBUTES_PATTERN = Pattern.compile("\\$\\{(.*?)\\}");

    @Override
    public String resolveDeploymentContextBasedVipAddresses(String vipAddressMacro) {
    if (vipAddressMacro == null) {
    return null;
    }

    String result = vipAddressMacro;

    //匹配${(.*?)}
    Matcher matcher = VIP_ATTRIBUTES_PATTERN.matcher(result);
    while (matcher.find()) {
    String key = matcher.group(1);
    String value = DynamicPropertyFactory.getInstance().getStringProperty(key, "").get();

    logger.debug("att:{}", matcher.group());
    logger.debug(", att key:{}", key);
    logger.debug(", att value:{}", value);
    logger.debug("");
    //将${(.*?)}替换为配置文件中对应的value
    result = result.replaceAll("\\$\\{" + key + "\\}", value);
    matcher = VIP_ATTRIBUTES_PATTERN.matcher(result);
    }

    return result;
    }
    }

ApplicationInfoManager

ApplicationInfoManager简介

所属包:com.netflix.appinfo.ApplicationInfoManager应用信息管理类,由InstanceInfoEurekaInstanceConfig生成。

ApplicationInfoManager源码

博主已添加中文注释,点击查看

EurekaClientConfig

EurekaClientConfig简介

所属包:com.netflix.discovery.EurekaClientConfigEureka-Client 配置接口,获取连接的 Eureka-Server 的地址、获取服务提供者列表的频率、注册自身为服务提供者的频率等等。

EurekaClientConfig源码

博主已添加中文注释,点击查看

EurekaClientConfig重要属性或者重要方法

  • getRegion()getAvailabilityZones():region和zone(或者Availability Zone)均是AWS的概念。在非AWS环境下,我们可以简单地将region理解为Eureka集群,zone理解成机房。Spring Cloud中默认的region是us-east-1 。具体可查看《周立 —— Region、Zone解析》
  • getEurekaServerServiceUrls():获取Eureka-Server的Url集合
  • 从Eureka-Server获取注册信息的相关方法:
    • getRegistryFetchIntervalSeconds():获取注册信息的时间间隔,单位为秒。默认为30s
    • getEurekaServiceUrlPollIntervalSeconds():向Eureka-Server获取Eureka服务地址的变化时间间隔,单位为秒。默认为 5 * 60 * 1000 s
    • getEurekaServerReadTimeoutSeconds():获取Eureka-Server读取超时时间,单位为秒。默认为8s
    • getBackupRegistryImpl():获取备份注册中心实现类。默认为null
    • shouldPreferSameZoneEureka():相同Zone的Eureka是否优先。默认为true
    • shouldDisableDelta():是否使用增量形式获取注册信息。默认为false
    • fetchRegistryForRemoteRegions():获取远程区域的注册信息。默认为null
    • shouldFilterOnlyUpInstances():是否只获取Up(启动)状态的实例。默认为true
    • shouldFetchRegistry():是否从Eureka-Server获取注册信息。默认为true
    • getRegistryRefreshSingleVipAddress():获取单个vip地址(虚拟IP地址)的注册信息。默认为null
    • getCacheRefreshExecutorThreadPoolSize():获取注册信息缓存刷新的线程池大小。默认为5
    • getCacheRefreshExecutorExponentialBackOffBound():获取注册信息缓存刷新执行超时后的延迟重试时间的最大倍数。默认为10
  • 向Eureka-Server注册自身服务的相关方法:
    • getInstanceInfoReplicationIntervalSeconds():获取向Eureka-Server同步实例信息的时间间隔,单位为秒。默认为30s
    • getInitialInstanceInfoReplicationIntervalSeconds():获取最初向Eureka-Server同步实例信息的时间间隔,单位为秒。默认为40s
    • getEurekaServerConnectTimeoutSeconds():获取Eureka-Server连接超时时间,单位为秒。默认为5s
    • shouldRegisterWithEureka():是否向Eureka-Server注册自身服务。默认为true
    • shouldUnregisterOnShutdown():当Eureka-Server关闭的时候,是否注销自己的服务。默认为true
    • getHeartbeatExecutorThreadPoolSize():获取心跳检测执行的线程池大小。默认为5
    • getHeartbeatExecutorExponentialBackOffBound():获取心跳检测执行超时后的延迟重试时间的最大倍数。默认为10
    • shouldEnforceRegistrationAtInit():是否在实例初始化的时候进行注册。默认为false

DefaultEurekaClientConfig

DefaultEurekaClientConfig简介

所属包:com.netflix.discovery.DefaultEurekaClientConfig基于配置文件的Eureka-Client配置实现类

DefaultEurekaClientConfig源码

博主已添加中文注释,点击查看

DefaultEurekaClientConfig重要属性或者重要方法

  • 其中属性和构造方法基本上都加了中文注释。
  • 其他实现方法基本类似,都是从配置文件中获取值,举一个例子:

    `getRegistryFetchIntervalSeconds()`:从配置文件中获取读取注册信息的时间间隔,并传一个默认值(这里是30),namespace后面的属性key都在PropertyBasedClientConfigConstants中。
    

DefaultEurekaClientConfigProvider

DefaultEurekaClientConfigProvider简介

所属包:com.netflix.discovery.providers.DefaultEurekaClientConfigProvider创建 DefaultEurekaClientConfig 的工厂

DefaultEurekaClientConfigProvider源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class DefaultEurekaClientConfigProvider implements Provider<EurekaClientConfig> {

@Inject(optional = true)
@EurekaNamespace
private String namespace;

private DefaultEurekaClientConfig config;

@Override
public synchronized EurekaClientConfig get() {
if (config == null) {
//根据命名空间是否为空来判断调用哪一个构造方法创建DefaultEurekaClientConfigProvider
config = (namespace == null)
? new DefaultEurekaClientConfig()
: new DefaultEurekaClientConfig(namespace);

// TODO: Remove this when DiscoveryManager is finally no longer used
DiscoveryManager.getInstance().setEurekaClientConfig(config);
}

return config;
}
}

很简单的一个类,不做过多的分析。

EurekaTransportConfig

EurekaTransportConfig简介

所属包:com.netflix.discovery.shared.transport.EurekaTransportConfigEureka网络传输配置接口

EurekaTransportConfig源码

博主已添加中文注释,点击查看

EurekaTransportConfig重要属性或者重要方法

  • getSessionedClientReconnectIntervalSeconds():Eureka-Client 会话重新连接的时间间隔,单位为秒,默认为20 * 60s。
  • getRetryableClientQuarantineRefreshPercentage():请求失败的Eureka-Client隔离集合占Eureka-Client总数的占比,超过该比例会进行清空,默认为0.66。
  • Endpoint相关:
    • getAsyncResolverRefreshIntervalMs():异步解析 EndPoint 集群频率,单位为毫秒。默认为5 * 60 * 1000ms。
    • getAsyncResolverWarmUpTimeoutMs():异步解析器预热解析 EndPoint 集群超时时间,单位为毫秒。默认为5000s。
    • getAsyncExecutorThreadPoolSize():异步线程池大小,默认为5。

DefaultEurekaTransportConfig

DefaultEurekaTransportConfig简介

所属包:com.netflix.discovery.shared.transport.DefaultEurekaTransportConfig基于配置文件的网络传输配置实现类

DefaultEurekaTransportConfig源码

博主已添加中文注释,点击查看

DefaultEurekaTransportConfig重要属性或者重要方法

  • 其他实现方法基本类似,都是从配置文件中获取值,举一个例子:
    • getSessionedClientReconnectIntervalSeconds():Eureka-Client 会话重新连接的时间间隔,并传一个默认值(这里是20 * 60),namespace的属性key都在PropertyBasedTransportConfigConstants中。

LookupService

LookupService简介

所属包:com.netflix.discovery.shared.LookupService查找服务接口,可以获取应用集合和应用实例集合。

  • 在 Eureka-Client 里,EurekaClient 继承该接口。
  • 在 Eureka-Server 里,com.netflix.eureka.registry.InstanceRegistry 继承该接口。

LookupService源码

博主已添加中文注释,点击查看

EurekaClient

EurekaClient简介

所属包:com.netflix.discovery.EurekaClientEureka-Client接口

EurekaClient源码

博主已添加中文注释,点击查看

EurkeaClient重要属性或者重要方法

  • 获取应用集合:
    • getApplicationsForARegion(@Nullable String region):获取指定区域中的Applications。
    • getApplications(String serviceUrl):获取指定的Eureka服务地址中注册的应用集合。
  • 获取应用实例集合:
    • getInstancesByVipAddress(String vipAddress, boolean secure):获取指定VIP地址的实例列表。
    • getInstancesByVipAddress(String vipAddress, boolean secure, @Nullable String region):获取指定VIP地址和区域的实例信息列表。
    • getInstancesByVipAddressAndAppName(String vipAddress, String appName, boolean secure):获取指定VIP地址和appName的实例信息列表。
  • getAllKnownRegions():获取所有已知的区域。
  • getInstanceRemoteStatus():获取实例状态。
  • registerHealthCheck():Eureka-Client注册健康检查。
  • getHealthCheckHandler():获取健康监测处理器。
  • registerEventListener():Eureka-Client注册事件监听。
  • unregisterEventListener():Eureka-Client取消事件监听注册。
  • getEurekaClientConfig():获取Eureka-Client配置。
  • getApplicationInfoManager():获取应用信息管理器。

DiscoveryClient

DiscoveryClient类结构图

DiscoveryClient简介

所属包:com.netflix.discovery.DiscoveryClientEurekaClient接口的实现类,用于与 Eureka-Server 交互。包含方法:

  • 向 Eureka-Server 注册自身服务
  • 向 Eureka-Server 续约自身服务
  • 向 Eureka-Server 取消自身服务,当关闭时
  • 从 Eureka-Server 查询应用集合和应用实例信息
  • 本文主要介绍DiscoveryClient的初始化,其他方法后续文章会有介绍

DiscoveryClient源码

博主已添加中文注释,点击查看

DiscoveryClient重要属性或者重要方法

构造函数:

1
2
3
4
5
@Inject
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args,
Provider<BackupRegistry> backupRegistryProvider) {
//省略具体代码
}
  • 参数:

    • ApplicationInfoManager应用信息管理类,具体可查看ApplicationInfoManager小结。

    • EurekaClientConfigEureka-Client 配置接口,获取连接的 Eureka-Server 的地址、获取服务提供者列表的频率、注册自身为服务提供者的频率等等,具体可查看EurekaClientConfig小结。

    • AbstractDiscoveryClientOptionalArgsDiscoveryClient 可选参数抽象基类。该参数是选填参数,实际生产中很少使用,源码如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      public abstract class AbstractDiscoveryClientOptionalArgs<T> {
      /**
      * 健康检查回调的工厂
      */
      Provider<HealthCheckCallback> healthCheckCallbackProvider;

      /**
      * 健康检查处理器的工厂
      */
      Provider<HealthCheckHandler> healthCheckHandlerProvider;

      /**
      * 向Eureka-Server注册之前的处理器
      */
      PreRegistrationHandler preRegistrationHandler;

      /**
      * Jersey 过滤器集合
      */
      Collection<T> additionalFilters;

      /**
      * Jersey 客户端
      */
      EurekaJerseyClient eurekaJerseyClient;

      /**
      * 生成 Jersey 客户端工厂
      */
      TransportClientFactory transportClientFactory;

      /**
      * 生成 Jersey 客户端工厂
      */
      TransportClientFactories transportClientFactories;

      /**
      * Eureka 事件监听集合
      */
      private Set<EurekaEventListener> eventListeners;

      /**
      * ssl
      */
      private Optional<SSLContext> sslContext = Optional.empty();

      /**
      * 主机认证
      */
      private Optional<HostnameVerifier> hostnameVerifier = Optional.empty();

      //省略set方法
      }
    • Provider<BackupRegistry>备份注册中心接口,当 Eureka-Client 启动时,无法从 Eureka-Server 读取注册信息,就从备份注册中心读取注册信息 ,源码如下:

      1
      2
      3
      4
      5
      6
      7
      @ImplementedBy(NotImplementedRegistryImpl.class)
      public interface BackupRegistry {

      Applications fetchRegistry();

      Applications fetchRegistry(String[] includeRemoteRegions);
      }

      实现类源码如下(可以看出暂未提供合适的实现):

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      @Singleton
      public class NotImplementedRegistryImpl implements BackupRegistry {

      /**
      * 获取应用注册信息
      *
      * @return 应用列表对象 (默认为null)
      */
      @Override
      public Applications fetchRegistry() {
      return null;
      }

      /**
      * 获取应用注册信息
      *
      * @param includeRemoteRegions 远程区域列表
      * @return 应用列表对象(默认为null)
      */
      @Override
      public Applications fetchRegistry(String[] includeRemoteRegions) {
      return null;
      }
      }
  • 具体逻辑可查看源码,博主已添加中文注释

总结

我们可以看到 EurekaClient 的创建,先是通过 EurekaInstanceConfig 生成 InstanceInfo,再通过 EurekaInstanceConfig 和 InstanceInfo 生成 ApplicationInfoManager,最后 EurekaClientConfig 和 ApplicationInfoManager 生成 EurekaClient。

欢迎关注博主其他的文章。

感谢您的支持!

本文标题:Eureka源码—EurekaClient

文章作者:yoga

发布时间:2018年03月21日 - 20:03

原始链接:https://yoga0521.github.io/2018/03/21/Eureka源码—EurekaClient/

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。 转载请注明出处!