绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
领导“叕”让我研究 Eureka 源码:注册过程
2022-04-01 17:12:16

本文主要内容如下:

目录

Eureka Client 就是客户端,可以是 Eureka Server 自身,也可以是要注册的服务实例,比如订单服务、商品服务等。

后续讲到 @EnableEurekaClient 注解时,其实是将当前 Application 当作一个 eureka client,注册到 eureka 服务上。

那么 Eureka Client 是如何注册的呢?

我们可以通过 Eureka 源码提供的示例类 ExampleEurekaClient 来看下 Eureka Client 的构造和注册过程。

首先从 main 方法方法看起,但是只看 main 表面,看不出来注册的代码在哪,那我们就来研究下底层的源码。

public static void main(String[] args) throws UnknownHostException {

    injectEurekaConfiguration();

    ExampleEurekaClient sampleClient = new ExampleEurekaClient();

    // create the client
    ApplicationInfoManager applicationInfoManager = initializeApplicationInfoManager(new MyDataCenterInstanceConfig());
    EurekaClient client = initializeEurekaClient(applicationInfoManager, new DefaultEurekaClientConfig());

    // shutdown the client
    eurekaClient.shutdown();
}

接着我们来一步一步分析 main 里面做了什么事情。

先放一张时序图,下文会逐步讲解。

一、初始化配置

1.1 初始化变量

injectEurekaConfiguration() 方法初始化了 Eureka 的一些变量,比如端口号、当前服务的访问路径、是否需要抓取注册表信息等等。

private static void injectEurekaConfiguration() throws UnknownHostException {
    String myHostName = InetAddress.getLocalHost().getHostName();
    String myServiceUrl = "http://" + myHostName + ":8080/v2/";
    System.setProperty("eureka.name""eureka");
    System.setProperty("eureka.port""8080");
    ...
}

1.2 获取配置文件配置

在这一行代码中,将配置文件 eureka-client.properties 中的配置读取后,放到了 EurekaInstanceConfig 中。这个 EurekaInstanceConfig 是用来初始化 applicationInfoManager 信息管理器的。

看下面代码,创建了一个 MyDataCenterInstanceConfig,其实就是创建了 EurekaInstanceConfig。

new MyDataCenterInstanceConfig()

那 MyDataCenterInstanceConfig 和  EurekaInstanceConfig 是什么关系呢?

InstanceConfig 类图

从类图关系中可以看到 MyDataCenterInstanceConfig 继承 PropertiesInstanceConfig 类,实现了 EurekaInstanceConfig 接口。这种接口之前专门讲过,通过接口来获取配置信息,类似这种方法 getXX()。

然后在 PropertiesInstanceConfig  类的构造函数调用了一个工具类,读取了配置文件 eureka-client.properties 中的值。这个隐藏的有点深啊!

Archaius1Utils.initConfig(CommonConstants.CONFIG_FILE_NAME);

1.3 初始化实例信息

主要就是构造出 instanceInfo 实例信息。这个里面的信息包含了步初始化变量中的配置信息。

InstanceInfo instanceInfo = new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get();
intanceInfo 信息如下所示:

1.4 初始化实例信息管理器

就是将 instanceConfig 和 instanceInfo 交给实例信息管理器来管理。

applicationInfoManager = new ApplicationInfoManager(instanceConfig, instanceInfo);

二、构造 EurekaClient

2.1 构造流程

构造 eurekaClient 的代码

eurekaClient = new DiscoveryClient(applicationInfoManager, clientConfig);

DiscoveryClient 是 EurekaClient 的子类,构造 DiscoveryClient做了以下几件事:

构造 EurekaClient 流程
  • 加载配置文件
  • 初始化网络传输组件
  • 将服务实例配置、配置文件配置、网络传输组件都赋值给了 DiscoveryClient。
  • 初始化两个线程,一个用来心跳检测,一个用来刷新缓存。
  • 初始化网络通信组件 EurekaTransport
  • 尝试抓取注册表信息,如果没有抓取到,则从备用的注册表中获取。
  • 初始化调度任务的方法中,启动了定时调度任务:心跳检测 heartbeat、缓存刷新 cacheRefresh。(这两个功能在后续篇章中都会讲到,请持续关注)
  • 初始化调度任务的方法中,初始化了一个 InstanceInfoReplicator,用来向 eureka server 注册的。
  • 初始化调度任务的方法中,初始化了一个状态变更的监听器 StatusChangeListener,这个里面也有注册的逻辑。

注意:在初始化调度任务的方法,会根据是否设置了抓取注册表信息和是否注册将 eureka-client 注册到 eureka-server 来执行上面的初始化操作。

如下代码所示:


三、Eureka Client 注册

3.1 注册流程

Eureka Client 向 Server 注册的代码隐藏的比较深,很难找到,不是直接调用注册的方法,而是通过一个后台线程去做的,而且调用注册方法的类的名字起得也有争议,叫做 InstanceInfoReplicator,“Replicator” 是拷贝副本的意思,而注册其实不是拷贝副本,而是将新的注册信息发送到 eureka server 上去的,所以这个类的名字起得不太好,这也是容易造成找不到注册代码的一个原因。

下面来看下 eureka client 是怎么向 eureka server 注册的。

(1)注册是通过 InstanceInfoReplicator 类来注册的。它是在构造 DiscoveryClient 时创建出来的。

启动了一个延时 40 s 的线程,

instanceInfoReplicator.start(40); // 40 s后执行

(2)然后将一个标志位设置为 true,用来标记是否注册过了。

instanceInfo.setIsDirty();

(3)然后调用注册的方法

discoveryClient.register();

register() 里面的核心代码就是

httpResponse = eurekaTransport.registrationClient.register(instanceInfo);

返回的 httpResponse 大家可以想到这是一个 HTTP 请求,eureka client 注册时就是发送的 http 请求。

eurekaTransport:底层的传输组件,在初始化 DiscoveryClient 时初始化出来的。

registrationClient:它是一个抽象类,在初始化 DiscoveryClient  时,通过调用 scheduleServerEndpointTask() 初始化了专门用于注册的 registrationClient,这里就是 SessionedEurekaHttpClient。

instanceInfo:就是要发送给 eureka server 的当前实例信息,用来注册的信息。

(4)发送 post 注册请求

执行 register() 方法,发送注册请求的类是 AbstractJerseyEurekaHttpClient,这个类在工程 eureka-client-jersey2 里面,用到的是 Jersey 框架,国内用这个框架的不多,就是一个支持 restful 的 Java 框架,用深究,下篇还会讲到这一块。请求的 url 为

http://localhost:8080/v2/apps/EUREKA

注册的方法里面发送了 post 请求。至此,Client 就注册到 Server 那边了。

response = resourceBuilder
    .accept(MediaType.APPLICATION_JSON)
    .acceptEncoding("gzip")
    .post(Entity.json(info));

那么 Server 是如何将注册信息保存到自己注册表里面的呢? 下篇我们再来讲解。

四、总结

Eureka Client 向 Eureka Server 注册的过程:

(1)Eureka Client 初始化了一个 DiscoveryClient,抓取注册表,执行调度任务。

(2)InstanceInfoReplicator 对象启动了一个延迟 40 s 的后台线程,执行注册。

(3)然后使用 AbstractJersey2EurekaHttpClient 发送 post 请求,将 instanceInfo 实例信息发送给 Eureka Server。

时序图如下:

留个问题

我们使用 Eureka 时,Service 启动后,Eureka 很快就发现了 Service 的存在,如下图所示的控制台界面:

并不需要等待 40 s 才能注册到 Eureka,那这又是为什们呢?

好了,本篇接近尾声,下一篇,我们来看下 Eureka Server 是如何将 Eureka Client 发送过来的注册信息保存起来的。

- END -

分享好友

分享这个小栈给你的朋友们,一起进步吧。

悟空聊架构
创建时间:2022-03-24 15:16:28
悟空聊架构,悟空和他的朋友们,专注架构设计
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • 悟空聊架构
    栈主

小栈成员

查看更多
  • 只要快乐
  • ColorfulDick
  • cclan
  • 零度9527
戳我,来吐槽~