源码分析之Eureka客户端源码解析
说明
本文所分析代码版本为spring boot/cloud 2.2.6。
预备知识
一些注解的说明
eureka中用到几个比较有意思的注解,简化程序实现。
@ConfigurationProperties(“eureka.instance”)
表示从外部配置文件中(properties或是yml文件)读取”eureka.instance”对应的配置。
@ConditionalOnBean/@ConditionalOnClass
1 | @ConditionalOnBean // 当给定的在bean存在时,则实例化当前Bean |
可以参考这篇文章:SpringBoot(16)—@ConditionalOnBean与@ConditionalOnClass
比如EurekaClientAutoConfiguration类定义中,类上面注解了@ConditionalOnClass(EurekaClientConfig.class),表示当在类路径中存在EurekaClientConfig.class,则实例化当前EurekaClientAutoConfiguration。
@ImplementedBy
google guice注解,指定接口默认的实现类。
@Singleton
jdk 提供的注解,将当前类实现为单例模式。
eureka架构

eureka客户端源码
eureka客户端工作流程
\
下面将简要说明上图的过程。
eureka客户端比较关键的类如下:

其中,DiscoveryClient是核心,它实现了EurekaClient接口,是该接口的默认实现(@ImplementedBy传入的是DiscoveryClient.class)。另外,@Singleton注解声明了DiscoveryClient是单例。
DiscoverClient
该类的关键方法如下:
1 | //服务注册相关 |
其构造方法DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer)中,此方法中依次执行了 从eureka server中拉取注册表,服务注册,初始化发送心跳,缓存刷新(定时拉取注册表信息),按需注册定时任务等,贯穿了Eureka Client启动阶段的各项工作。
此处给出一些简单的分析:
1 | DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer) { |
DiscoveryClient构造方法小结
构造方法中主要进行如下工作:
- 初始化各种信息
- 从eureka server拉取注册表信息
- 向server注册自己
- 初始化3个任务
以下对重要过程进行分析:
拉取注册表过程
对应private boolean fetchRegistry(boolean forceFullRegistryFetch)方法,参考注释、源码可以知道逻辑如下:
1 | 如果增量式拉取被禁止或第一次拉取注册表,则进行全量拉取:getAndStoreFullRegistry()。 |
全量拉取 getAndStoreFullRegistry()
1 | 进入getAndStoreFullRegistry() 方法,有一方法:eurekaTransport.queryClient.getApplications。 |
增量拉取getAndUpdateDelta(applications)
1 | 回到刚才的fetchRegistry方法中,getAndUpdateDelta,增量拉取。通过getDelta方法,看到实际拉取的地址是:apps/delta,如果获取到的delta为空,则全量拉取。 |
服务注册过程
1 | DiscoveryClient构造函数中,拉取fetchRegistry完后进行register注册。由于构造函数开始时已经将服务实例元数据封装好了instanceInfo,所以此处之间向server发送instanceInfo, |
初始化3个定时任务
有3个:
- 心跳定时任务:client会定时向server发送心跳,维持自己服务租约的有效性,用心跳定时任务实现;
- 缓存定时任务:server中会有不同的服务实例注册或是下线,所以client需要定时从server拉取注册表信息,用缓存定时任务实现。
- 按需注册的定时任务,当instanceinfo和status发生变化时,需要向server同步,去更新自己在server中的实例信息。保证server注册表中服务实例信息的有效和可用。
参见initScheduledTasks()。
心跳定时任务和缓存刷新定时任务是有scheduler 的 schedule提交的,查看scheduler变量声明上,看到注释:
1 | A scheduler to be used for the following 3 tasks: |
由此可以知道循环逻辑是由TimedSuperVisorTask实现的。
1 | //心跳定时任务 |
服务下线
服务下线:在应用关闭时,client会向server注销自己,在Discoveryclient销毁前,会执行下面清理方法。
1 | //此方法上有一个注解,表示:在销毁前执行此方法。unregisterStatusChangeListener注销监听器。 |
更多
更进一步的启动流程分析,可以参考这篇文章:Eureka之Client端注册
下面这张图即来自该文章,感觉还可以。

在一个spring cloud项目中,eureka客户端中的关键类DiscoveryClient是怎样实例化的?
首先,需要了解spring boot如何使用spring factories机制加载第三方库,这个可以参考我之前整理的这篇文章:源码分析之Spring Boot如何利用Spring Factories机制进行自动注入。
以笔者本人使用eureka时所使用的spring-cloud-netflix-eureka-client-2.2.2.RELEASE为例,在pom文件中引入该包后,可以IDEA中看到该包下包含了spring.factories

该文件内容如下:
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ |
我们点EurekaDiscoveryClientConfigServiceBootstrapConfiguration,可以看到如下代码:
1 |
|
在EurekaClientAutoConfiguration中,可以找到如下代码:
1 | CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager, |
而CloudEurekaClient类,实际上继承自DiscoveryClient:
1 | public class CloudEurekaClient extends DiscoveryClient { |
所以,在spring boot启动时,将通过spring factories机制,实例化DiscoveryClient。
















