Spring Cloud Eureka 源码分析 —— Client端

如题所述

第1个回答  2022-07-21

eureka的client端主要完成几件事情:

整个源码有几个重点类值得关注:

EurekaClientConfigBean 对应的配置前缀是eureka.client,从配置文件读取的配置会保存到此bean中

EurekaInstanceConfigBean 对应的配置前缀是eureka.instance,从配置文件读取的实例信息配置会保存到此bean中

EurekaServiceRegistry 实现了ServiceRegistry,是实例注册的具体实现类,内部通过register完成服务注册事件的发送动作。

EurekaRegistration 是真正被注册的对象,内部封装了客户端所有的注册信息,是org.springframework.cloud.client.serviceregistry.ServiceInstance此标准的具体实现类

首先创建了初始化状态的InstanceInfo,根据配置对InstanceInfo的大量属性赋值。
构建ApplicationInfoManager内部封装了注册到eureka的应用信息,包括实例信息,参数配置,实例状态等。
InstanceInfo对象也会被设置到到ApplicationInfoManager中。

这个bean非常重要,在内部完成了几乎所有客户端操作的定义,是发起操作的客户端类。重点在构造方法中实现,下文会具体分析。

eureka客户端的注册动作,通过SmartLifecycle来触发,对应的实现类是EurekaAutoServiceRegistration

直接看start方法,根据初始化参数,直接进入if方法。有两个关键方法,分别是register()开始注册, publishEvent 发布当前实例注册的事件。

maybeInitializeClient 触发了后续两个重要的bean: ApplicationInfoManager 和 EurekaClient 的实例化过程。
ApplicationInfoManager 存放了InstanceInfo的信息和InstanceConfig的所有配置信息。
EurekaClient (CloudEurekaClient) 在构造过程中,完成了整个客户端的注册、向服务端进行数据同步,schedule任务的定义和开启。

依次介绍这两个类的创建过程。

bean的定义在上面的AutoConfiguration中

这里首先通过工厂创建了一个InstanceInfo的对象,create方法将EurekaInstanceConfig里的所有配置通过builder模式赋值到InstanceInfo中。
并在内部初始化了两个属性,listeners和instanceStatusMapper。

bean的定义在上面的AutoConfiguration中

先调用父类的super构造方法

在构造方法的初始逻辑前,先初始化了BackupRegistry的对象,这个是当eureka所有的url都无法连接时,会按照backupRegistryImpl指定的自定义类来实现,默认使用NotImplementedRegistryImpl,内部什么都不处理。

这个fetchRegistry方法会在启动时调用,以及schedule任务执行时,每次刷新客户端缓存时调用。主要做了几件事情。

这里的apps就是从eureka服务端拉取的全量注册表信息,如下图

先将服务远程的当前状态跟上一次拉取的状态进行比较,如果一致,则结束,不一致则发出一个StatusChangeEvent事件。

如果成功从eureka 服务端拉取注册表成功,则fetchRegistry返回true。

这里还需要 重点说明下run的实现
scheduler.schedule在调度任务时,只传了delay的时间,并没有传周期时间,而执行周期其实是会动态变化的,这里的动态变化是通过scheduler.schedule的递归来完成。

可以看到在try块中,delay的值会被重置,并且如果出现超时,则将newDelay可能设置成2倍的时间,再在finally中再次执行schedule,延迟的时间就是2倍的delay, 这是一种动态周期的schedule实现方案

这个task其实就是调用了fetchRegistry,拉取最新的注册表,刷新本地cache。

这个task就是发起了一个http请求,调用了sendHearBeat方法,发起了一次心跳续约。

InstanceInfoReplicator 是实例信息的同步器,作用是当发生变更时(状态、地址、ip、配置参数值等),将新的InstanceInfo同步给eureka服务端。
这里的三个方法:
start() :在初始化时,调用start开启schedule任务,每隔一段时间来调用run()检测变更。
onDemandUpdate() :在触发状态变更时,作为listener来调用,也会调用run()检测变更。
run() :检测当前InstanceInfo是否跟上次相同,如果出现变更,则调用 discoveryClient.register(); 将新的信息同步到eureka服务端。依据则是instanceInfo是否被标记为 isDirty

而标记的依据在 discoveryClient.refreshInstanceInfo(); 中实现。