【Spring Cloud】Eureka-Client 源码解读|周末学习

本文已参与周末学习计划,点击链接查看详情 链接

一、前言

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

用技巧连蒙带猜:

  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. 创建服务实例管理器

    1. 构建服务实例(InstanceInfo
    2. 构建服务实例管理器(ApplicationInfoManager
    ApplicationInfoManager applicationInfoManager = initializeApplicationInfoManager(new MyDataCenterInstanceConfig());
    复制代码
  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;
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享