作者:叩丁狼教诲,陈刚
对付一个精良的程序员而言,一个技能不仅要会用,还要知道他的实现事理和思想,即不仅要知其然还要知其以是然,这样我们写代码才会特殊自傲,涌现bug才能很快定位到问题所在。接下来我们就来大略磋商一下SpringCloud的实现事理,即:源码剖析
一.做事注册

做事注册与创造是SpringCloud最根本的部分,我们就从这部分开始动手剖析,我们来看一下我们第一章写的做事注册案例,图:
我们知道当做事(Eureka Client)启动会主动向 EurekaServer注书籍身,而消费者做事须要调用供应者做事实现消费时是须要向EurekaServer获取目标做事的做事地址等信息,那么我们就先来剖析一下EurekaClient是如何实现做事注册的。
回忆一下我们布局一个EurekaClient做事实例的时候须要做哪些事情呢?
1.在主程序配置类打开 @EnableDiscoveryClient(或EnableEurekaClient)标签开启EurekaClient功能
2.在applicatiton.properties中做一些做事的根本配置和注册中央地址配置
那么我们就沿着这个2个点来切入源码:
点开 @ EnableDiscoveryClient 源码如下:
EnableDiscoveryClient的文档注释:
Annotation to enable a DiscoveryClient implementation
见告我们:这个EnableDiscoveryClient这个标签是用来开启 DiscoveryClient的,那么我们来看一下 org.springframework.cloud.client.discovery.DiscoveryClient 如下:
DiscoveryClient 的注释:
DiscoveryClient represents read operations commonly available to Discovery service such as Netflix Eureka or consul.io
见告我们这个接口定义了做事常日的读取操作的抽象方法,剖析这个接口下的三个方法,浸染分别是:获取备注 ,根据做事id获取做事列表,获取所有的做事的id
这个接口貌似到顶了,我们看一下他的实现类你可以看到一个让你很亲切的名字 EurekaDiscoveryClient(Eureka的做事客户端) 如下:
可以看到 EurekaDiscoveryClient 依赖了 EurekaClient 接口 ,而对付getServices和 getInstances方法的实当代码中都是调用了EurekaClient的方法,即:“this.eurekaClient…”
连续跟踪 EurekaClient 的源码:
EurekaClient 实现了 LookupService接口,连续跟踪 LookupService
从注释 :Lookup service for finding active instances.
可以知道,这个lookupService 的浸染是用于查找活动实例的做事。并供应了一些查找方法
然而在 EurekaDiscoveryClient 中利用的到底是 EurekaClient 哪个实现类的实例呢?我们连续跟踪一下 EurekaClient的实现类 com.netflix.discovery.DiscoveryClient ,从包名可以知道这个类是netflix供应的:
翻译一下这个类的文档注释,大存问思为:
DiscoveryClient 和 Eureka Server 类进行交互
向 Eureka Server 注册做事
向 Eureka Server租约续期
做事关闭,取消租约续期
获取做事列表
Eureka client须要配置 Eureka Server的url列表
看到这里我们大概知道,实在真正实现做事创造的Netflix包中的com.netflix.discovery.DiscoveryClient类,我们整理一下这几个类/接口的关系图如下:
接下来我们详细看一下DiscoveryClient是如何实现做事注册和创造等功能的,找到DiscoveryClient中的代码:
从方法名字就可以看出方法里面初始化了很多的定时任务,
instanceInfo:是根据做事配置创建出来的做事实例干系信息工具,是在EurekaClientAutoConfiguration类中的 eurekaApplicationInfoManager方法中被创建的
而 EurekaInstanceConfig 便是application.properties配置的绑定
而instanceInfoReplicator 是一个线程工具,他的代码如下:
/ A task for updating and replicating the local instanceinfo to the remote server. Properties of this task are: - configured with a single update thread to guarantee sequential update to the remote server - update tasks can be scheduled on-demand via onDemandUpdate() - task processing is rate limited by burstSize - a new update task is always scheduled automatically after an earlier update task. However if an on-demand task is started, the scheduled automatic update task is discarded (and a new one will be scheduled after the new on-demand update). @author dliu /class InstanceInfoReplicator implements Runnable {
翻译注释知道 InstanceInfoReplicator的浸染是用于更新本地instanceinfo并将其复制到远程做事器的任务 ,实在便是把本地做事实例的干系配置信息(地址,端口,做事名等)发送到注册中央完成注册
我们来跟踪一下他的 run方法 :
定位关键代码: discoveryClient.register(); 这里便是在实现做事注册,连续跟踪进去:
这里通过调用:eurekaTransport.registrationClient.register(instanceInfo);实现注册,而instanceInfo实在便是当前做事实例的元数据(配置信息),连续跟踪
翻译 Low level Eureka HTTP client API. 得知这里是一个HTTP客户真个API,那么我们可以大胆预测,register方法的实现实在便是通过 rest 要求的办法。连续往下追踪该方法
看到这里我们该当就明白了,在register方法中获取到了 serviceUrl 即配置文件中的注册做事地址,,把InstanceInfo作为参数,底层通过EurekaHttpClient(Rest办法)来发要求要求,实现做事注册。
做事获取
连续看com.netflix.discovery.DiscoveryClient的initScheduledTasks()方法,里面还有两个定时任务
我们先看第一个任务:做事获取 ,
clientConfig.getRegistryFetchIntervalSeconds()是从配置中获取做事清单获取韶光间隔,他是实行线程是new HeartbeatThread(),我们跟踪进去
fetchRegistry:便是获取注册表(注册做事清单)的方法
etAndStoreFullRegistry(); 得到并存储完全的注册表,跟踪进去
我们可以看到 eurekaTransport.queryClient.这样的代码实在便是通过Rest办法去获取做事清单 末了通过 localRegionApps.set把做事存储到本地区域
做事续约
连续看 com.netflix.discovery.DiscoveryClient 中的 initScheduledTasks() 方法中的另一个定时任务
heartbeat :利用心跳机制实现做事续约,即每间隔多少秒去要求一下注册中央证明做事还在线,防止被剔除。
renewalIntervalInSecs :便是心跳韶光间隔 对应的配置:
eureka.instance.lease-renewal-interval-in-seconds=30
eureka.instance.lease-expiration-duration-in-seconds=90
我们来看一下他的执线程:HeartbeatThread
不丢脸出他是通过 eurekaTransport.registrationClient.sendHeartBeat:去发送心跳 ,依然是Rest办法