服务注册与发现组件 Eureka 客户端实现原理解析

前面的文章介绍了,如何使用服务注册发现组件: Eureka,并给出使用示例。本文在此基础上,将会讲解 Eureka 客户端实现的内幕,结合源码深入实现的细节,知其所以然。客户端需要重点关注以下几点:

  • 从Eureka Server中拉取注册表信息
  • 全量拉取注册表信息
  • 增量式拉取注册表信息
  • 注册表缓存刷新定时器与续租(心跳)定时器
  • 服务注册与服务按需注册
  • 服务实例的下线

本文摘录于笔者出版的书籍 《Spring Cloud 微服务架构进阶》

Eureka Client 结构

在Finchley版本的SpringCloud中,不需要添加任何的额外的注解就可以登记为Eureka Client,只需要在pom文件中添加spring-cloud-starter-netflix-eureka-client的依赖。

为了跟踪Eureka的运行机制,读者可以打开SpringBoot的Debug模式来查看更多的输出日志:

logging:
  level:
    org.springframework: DEBUG

查看spring-cloud-netflix-eureka-clientsrc/main/resource.META-INF/spring.factories,查看Eureka Client有哪些自动配置类:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration

org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.netflix.eureka.config.EurekaDiscoveryClientConfigServiceBootstrapConfiguration

排除掉与配置中心相关的自动配置类,从中可以找到三个与Eureka Client密切相关的自动配置类:

  • EurekaClientAutoConfiguration
  • RibbonEurekaAutoConfiguration
  • EurekaDiscoveryClientConfiguration

下面将对这些类进行分析,看看一个正常的Eureka Client需要做哪一些初始化配置。

EurekaClientAutoConfiguration

Eureke Client的自动配置类,负责了Eureka Client中关键的bean的配置和初始化,以下是其内比较重要的bean的介绍与作用。

EurekaClientConfig

提供了Eureka Client注册到Eureka Server所需要的配置信息,SpringCloud为其提供了一个默认配置类的EurekaClientConfigBean,可以在配置文件中通过前缀eureka.client+属性名进行覆盖。

ApplicationInfoManager

该类管理了服务实例的信息类InstanceInfo,其内包括Eureka Server上的注册表所需要的信息,代表了每个Eureka Client提交到注册中心的数据,用以供服务发现。同时管理了实例的配置信息EurekaInstanceConfig,SpringCloud提供了一个EurekaInstanceConfigBean的配置类进行默认配置,也可以在配置文件application.yml中通过eureka.instance+属性名进行自定义配置。

EurekaInstanceConfigBean

继承了EurekaInstanceConfig接口,是Eureka Client注册到服务器上需要提交的关于服务实例自身的相关信息,主要用于服务发现:

通常这些信息在配置文件中的eureka.instance前缀下进行设置,SpringCloud通过EurekaInstanceConfigBean配置类提供了相关的默认配置。以下是一些比较关键的属性,这些信息都将注册到注册中心上。


public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, EnvironmentAware {
   

// 服务实例的应用名
private String appname; 
// 服务实例的Id,通常和appname共同唯一标记一个服务实例
private String instanceId; 
// 自定义添加的元数据,由用户使用以适配扩展业务需求
private Map<String, String> metadataMap;
// 如果服务实例部署在AWS上,该类将持有服务实例部署所在的数据中心的准确信息
private DataCenterInfo dataCenterInfo;
// 服务实例的Ip地址
private String ipAddress;
// 服务实例主页地址
private String homePageUrl;
// 服务实例健康检查地址
private String healthCheckUrlPath;
// 服务实例的状态地址
private String statusPageUrlPath

.....
}

DiscoveryClient

这是SpringCloud定义的用来服务发现的顶级接口,在Netflix Eureka或者consul都有相应的具体实现类,提供的方法如下:


public interface DiscoveryClient {
   

   // 获取实现类的描述
	String description();

	// 通过服务Id获取服务实例的信息
	List<ServiceInstance> getInstances(String serviceId);

	// 获取所有的服务实例的Id
	List<String> getServices();

}

其在Eureka方面的实现的相关的类结构图:

EurekaDiscoveryClient继承了DiscoveryClient,但是通过查看EurekaDiscoveryClient中的代码,会发现它是通过组合类EurekaClient实现接口的功能,如下的getInstance接口:

@Override
public List<ServiceInstance> getInstances(String serviceId) {
   
	List<InstanceInfo> infos = this.eurekaClient.getInstancesByVipAddress(serviceId,false);
	List<ServiceInstance> instances = new ArrayList<>();
	for (InstanceInfo info : infos) {
   
		instances.add(new EurekaServiceInstance(info));
	}
	return instances;
}

EurekaClient来自于com.netflix.discovery包中,其默认实现为com.netflix.discovery.DiscoveryClient,这属于eureka-client的源代码,它提供了Eureka Client注册到Server上、续租,下线以及获取Server中注册表信息等诸多关键功能。SpringCloud通过组合方式调用了Eureka中的的服务发现方法,关于EurekaClient的详细代码分析将放在客户端核心代码中介绍。为了适配spring-cloud,spring提供了一个CloudEurekaClient继承了com.netflix.discovery.DiscoveryClient,同时覆盖了onCacheRefreshed防止在spring-boot还没初始化时调用该接口出现NullPointException

上述的几个配置类之间的关系非常紧密,数据之间存在一定的耦合,所以下面介绍一下它们之间的关系

首先是EurekaInstanceConfig,代码位于EurekaClientAutoConfiguration

@Bean
@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)
public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) {
   
	// 从配置文件中读取属性
	String hostname = getProperty("eureka.instance.hostname");
	boolean preferIpAddress = Boolean.parseBoolean(getProperty("eureka.instance.prefer-ip-address"));
	String ipAddress = getProperty("eureka.instance.ipAddress");
	boolean isSecurePortEnabled = Boolean.parseBoolean(getProperty("eureka.instance.secure-port-enabled"));

	String serverContextPath = env.getProperty("server.context-path", "/");
	int serverPort = Integer.valueOf(env.getProperty("server.port", env.getProperty("port", "8080")));

	Integer managementPort = env.getProperty("management.server.port", Integer.class);// nullable. should be wrapped into optional
	String managementContextPath = env.getProperty("management.server.context-path");// nullable. should be wrapped into optional
	Integer jmxPort = env.getProperty("com.sun.management.jmxremote.port", Integer.class);//nullable
	EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
   // 设置非空属性
	instance.setNonSecurePort(serverPort);
	instance.setInstanceId(getDefaultInstanceId(env));
	instance.setPreferIpAddress(preferIpAddress);
	if (StringUtils.hasText(ipAddress)) {
   
		instance.setIpAddress(ipAddress);
	}

	if(isSecurePortEnabled) {
   
		instance.setSecurePort(serverPort);
	}

	if (StringUtils.hasText(hostname)) {
   
		instance.setHostname(hostname);
	}
	String statusPageUrlPath = getProperty("eureka.instance.status-page-url-path");
	String healthCheckUrlPath = getProperty("eureka.instance.health-check-url-path")
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值