【Spring Cloud】Eureka-Client 源码解读
一、前言
看源码:抓大放小,先主流程,再细枝末节。
用技巧连蒙带猜:
看方法名(英文名)
看注释
搭建环境:
// 定位: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());
    ... ...
}
复制代码过程如下:
初始化
eureka环境变量创建
eureka服务,会有一个eureka-client创建服务实例管理器
ApplicationInfoManager applicationInfoManager = initializeApplicationInfoManager(new MyDataCenterInstanceConfig());
复制代码构建服务实例(
InstanceInfo)构建服务实例管理器(
ApplicationInfoManager)创建
eureka-client(通过构造DiscoveryClient)处理配置
服务的注册和注册表的抓取(初始化网络通信组件)
创建几个线程池,启动调度任务
注册监控项
(2)eureka-client 如何服务注册的?
针对注册,提出问题:
什么时候进行服务注册?初始化
eureka-client时候
eureka-client的服务注册,是在InstanceInfoReplicator中完成的。
服务注册做哪些操作?主要发送
HTTP请求
针对这个两个问题,来看下源码。虽然这部分的源码写的不好,但也可以学习了解下他人的思路。
这部分源码比较难找,实际是在创建 DiscoveryClient 的 initScheduledTasks()(初始化调度任务)
// 定位:com.netflix.discovery.DiscoveryClient.java
private void initScheduledTasks() {
    // InstanceRegisterManager:实例注册管理器,专门来管理实例注册
    // 传参:默认 40秒
    instanceInfoReplicator.start(...);
}
复制代码启动实例注册管理器(
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);
    }
}
复制代码执行
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);
    }
}
复制代码重要:注册
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
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论
