【Spring Cloud】Eureka-Client 源码解读

愿天堂没有BUG

共 4475字,需浏览 9分钟

 · 2021-06-02

一、前言

看源码:抓大放小,先主流程,再细枝末节。

用技巧连蒙带猜:

  1. 看方法名(英文名)

  2. 看注释

搭建环境:

// 定位:eureka-examples 模块下
// 修改 ExampleEurekaClient.java

// 1. 增加一个方法,用于初始化环境变量,方便调试
private static void injectEurekaConfiguration() throws UnknownHostException {
String myHostName = InetAddress.getLocalHost().getHostName();
String myServiceUrl = "http://" + myHostName + ":8080/v2/";

System.setProperty("eureka.region", "default");
System.setProperty("eureka.name", "eureka");
System.setProperty("eureka.vipAddress", "eureka.mydomain.net");
System.setProperty("eureka.port", "8080");
System.setProperty("eureka.preferSameZone", "false");
System.setProperty("eureka.shouldUseDns", "false");
System.setProperty("eureka.shouldFetchRegistry", "false");
System.setProperty("eureka.serviceUrl.defaultZone", myServiceUrl);
System.setProperty("eureka.serviceUrl.default.defaultZone", myServiceUrl);
System.setProperty("eureka.awsAccessId", "fake_aws_access_id");
System.setProperty("eureka.awsSecretKey", "fake_aws_secret_key");
System.setProperty("eureka.numberRegistrySyncRetries", "0");
}


// 2. 在 main 方法添加
public static void main(String[] args) throws UnknownHostException {

// 添加如下这行
injectEurekaConfiguration();
... ...
}
复制代码



二、从源码中学到了什么



三、直接怼源码

(1)eureka-client 如何启动(初始化)?

代码如下:

// 定位:com.netflix.eureka.ExampleEurekaClient.java
public static void main(String[] args) throws UnknownHostException {
// 1. 初始化 eureka 环境变量
injectEurekaConfiguration();
// 2. 创建 eureka 服务
ExampleEurekaClient sampleClient = new ExampleEurekaClient();
// 3. 创建服务实例管理器
ApplicationInfoManager applicationInfoManager =
initializeApplicationInfoManager(new MyDataCenterInstanceConfig());
// 4. 创建 eureka-client
EurekaClient client =
initializeEurekaClient(applicationInfoManager, new DefaultEurekaClientConfig());

... ...
}
复制代码

过程如下:

  1. 初始化 eureka 环境变量

  2. 创建 eureka 服务,会有一个 eureka-client

  3. 创建服务实例管理器

    ApplicationInfoManager applicationInfoManager = initializeApplicationInfoManager(new MyDataCenterInstanceConfig());
    复制代码
    1. 构建服务实例(InstanceInfo

    2. 构建服务实例管理器(ApplicationInfoManager

  4. 创建 eureka-client(通过构造 DiscoveryClient

    • 处理配置

    • 服务的注册和注册表的抓取(初始化网络通信组件)

    • 创建几个线程池,启动调度任务

    • 注册监控项



(2)eureka-client 如何服务注册的?

针对注册,提出问题:

  1. 什么时候进行服务注册?初始化 eureka-client 时候

eureka-client 的服务注册,是在 InstanceInfoReplicator 中完成的。

  1. 服务注册做哪些操作?主要发送 HTTP 请求

针对这个两个问题,来看下源码。虽然这部分的源码写的不好,但也可以学习了解下他人的思路。

这部分源码比较难找,实际是在创建 DiscoveryClientinitScheduledTasks()(初始化调度任务)

// 定位:com.netflix.discovery.DiscoveryClient.java
private void initScheduledTasks() {
// InstanceRegisterManager:实例注册管理器,专门来管理实例注册
// 传参:默认 40秒
instanceInfoReplicator.start(...);
}
复制代码
  1. 启动实例注册管理器(InstanceRegisterManager

// 定位:com.netflix.discovery.InstanceInfoReplicator.java
public void start(int initialDelayMs) {
// 原子操作
if (started.compareAndSet(false, true)) {
// 1. 先设置 isDirty = true
instanceInfo.setIsDirty();
// 2. 调度器执行,将自身传入,并且调度时间默认为 40 秒
// 所以会执行 InstanceInfoReplicator.run() 方法
Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS);
scheduledPeriodicRef.set(next);
}
}
复制代码
  1. 执行 InstanceInfoReplicator.run()

// 定位:com.netflix.discovery.InstanceInfoReplicator.java
// 会发现:class InstanceInfoReplicator implements Runnable,是可创建线程的。
public void run() {
try {
// 1. 刷新了服务实例的信息,拿到服务的状态
discoveryClient.refreshInstanceInfo();
Long dirtyTimestamp = instanceInfo.isDirtyWithTime();
if (dirtyTimestamp != null) {
// 2. 注册:因为之前已经设置 isDirty = true,所以下面直接注册
discoveryClient.register();
// 3. 设置 isDirty = false
instanceInfo.unsetIsDirty(dirtyTimestamp);
}
} catch (Throwable t) {
logger.warn("There was a problem with the instance info replicator", t);
} finally {
// 4. 再次把自己丢进调度线程中
Future next =
scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);
scheduledPeriodicRef.set(next);
}
}
复制代码
  1. 重要:注册 discoveryClient.register();

// 定位:com.netflix.discovery.DiscoveryClient.java
boolean register() throws Throwable {
EurekaHttpResponse<Void> httpResponse;
try {
// 发送 HTTP 请求
httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
... ...
}
... ...
return httpResponse.getStatusCode() == 204;
}


作者:卷卷啊
链接:https://juejin.cn/post/6968080788868825118
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


浏览 27
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报