深入理解SpringCloud源码探究篇 | Eureka服务端源码分析

SpringCloud系列:

  1. SpringCloud入门必看例子
  2. 深入理解SpringCloud源码探究篇 | Eureka服务端源码分析
  3. 深入理解SpringCloud源码探究篇 | Eureka客户端源码分析
  4. 深入理解SpringCloud源码探究篇 | ribbon源码分析
  5. 深入理解SpringCloud源码探究篇 | Feign源码分析

虽然说官方已经发布Eureka不在维护的通知,但是还是需要对我们用过的Eureka进行深入了解的,因为这些玩意都是大同小异的。

下面先利用白话文分析Eureka服务端的实现原理:

eureka服务端:
    EurekaServerAutoConfiguration自动配置类,注册各种bean,包括PeerAwareInstanceRegistry用于服务注册(实际就是父类AbstractInstanceRegistry提供的ConcurrentHashMap存放服务注册列表:registry)、以及jersey。eureka是利用jersey提供接口给客户端访问注册服务和获取服务列表的,jerseyApplication将注册DefaultResourceConfig的bean交由spring容器,这里扫描获取所有@Path注解的类(这是jersey的注解相当springmvc的@RequestMapping)放入DefaultResourceConfig交由spring容器即可。这样就启动了jersey的访问。

   这里我们直接从服务注册接口和服务查询接口开始对eureka的剖析。ApplicationResource提供注册接口addInstance,ApplicationsResource提供服务列表获取getContainers;

    ApplicationResource.addInstance:接收服务注册请求,将InstanceInfo服务信息调用PeerAwareInstanceRegistry.register将其信息组装后放入名叫registry(实际就是父类AbstractInstanceRegistry提供的ConcurrentHashMap存放服务注册列表:registry))的一个ConcurrentHashMap中,这样就完成了服务注册操作。
    ApplicationsResource.getContainers:接收服务列表获取访问,调用ResponseCacheImpl.getGZIP其实际就是通过readWriteCacheMap(LoadingCache)中获取到信息,而这这个readWriteCacheMap信息是在实例化ResponseCacheImpl时进行初始化数据的,初始化是真正调用到的是ResponseCacheImpl.generatePayload进行readWriteCacheMap赋值,而这里就是从AbstractInstanceRegistry的registry.entrySet()获取所有服务信息将其进行处理返回。
    服务端通过客户端发送的心跳进行服务的续约(续约时间固定),当超过续约时间未收到客户端心跳则会进行剔除操作,当然服务端下线时也会主动触发请求服务端进行服务剔除,服务续约请求:InstanceResource.renewLease()进行服务时间的刷新;
    主动触发剔除请求:InstanceResource.cancelLease()调用的是AbstractInstanceRegistry.internalCancel()进行服务删除;
    定时查看对比各服务的续约时间是否超期,是则发起剔除操作:AbstractInstanceRegistry.evict()查询服务是否过期,过期的调用AbstractInstanceRegistry.internalCancel()进行服务删除

eureka服务端核心大致的实现如上面所说, 下面进行源码的探究:

 

EurekaServerAutoConfiguration自动配置类

我们在demo中使用启动eureka服务端是启动类会加上@EnableEurekaServer:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第1张图片

该注解import一个类EurekaServerMarkerConfiguration:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第2张图片

该类实际上什么都没有,就是注册了个空的Marker。

我们回到EurekaServerAutoConfiguration自动配置类中你会发现,这个Marker是启动自动配置类的条件标识:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第3张图片

接着我们来看看这个自动配置类做了些什么操作,其他多余的我就不列了,就绕着前面的白话文里提到的PeerAwareInstanceRegistry和jersey;

 

服务注册核心PeerAwareInstanceRegistry类:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第4张图片

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第5张图片

 

JerseyApplication:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第6张图片

这里正如前面所说的扫描出所有@Path和@Provider的类放入DefaultResourceConfig,这里关于jersey知识我就不这里描述了,不懂的可以自行百度。

 

这里我们注册的比较重要的几个jersey接口,其中有ApplicationResource,ApplicationsResource,InstanceResource。

ApplicationResource该类提供了服务注册接口

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第7张图片

 深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第8张图片

我们先来分析这个服务注册的过程

首先从接口中我们拿到客户端提交过来的信息InstanceInfo,该接口其他的各种细节操作我们不需要关注他,拿到info后调用

registry.register(info, "true".equals(isReplication));

也就是调用AbstractInstanceRegistry.register:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第9张图片

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第10张图片

 到这里我们可以看到其实际上就是操作一个叫做registry的ConcurrentHashMap【ConcurrentHashMap>> 】,具体存放信息结构如下:

{
    "客户端服务": { // 服务名
        "实例的唯一ID": { // 实例标识符
            "lease": { // 持有实例信息
                "instanceInfo": { // 实例信息
                    "appName": "客户端服务",
                    "instanceId": "实例的唯一ID",
                    "ipAddr": "IP地址",
                    "port": "调用端口"
                }
            }
        }
    }
}

服务的注册大概就是这样子,接着就是服务列表的获取接口 

ApplicationsResource,提供了所有注册过的服务列表获取:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第11张图片

其中重点我们可以看下

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第12张图片 通过调用ResponseCacheImpl.getGZIP来获取

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第13张图片

而这个又接着getValue:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第14张图片

实际上这个值得获取来自于readWriteCacheMap,然而这个readWriteCacheMap的数据又是从哪而来的呢?

ResponseCacheImpl在被构造时会进行readWriteCacheMap的数据初始化操作:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第15张图片

这里调用generatePayload:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第16张图片

前面我们传入的得是ALL_APPS,我们来看看这块数据的获取,调用的是AbstractInstanceRegistry.getApplicationsFromMultipleRegions最终获取的部分核心内容如下:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第17张图片

这里的registry不正是我们前面注册时存放进去的服务信息嘛,然后接着获取所有进行遍历构造出Applications对象然后进行返回。也就是说前面readWriteCacheMap获取到的就是Applications信息。到这里服务的获取我们也就明白了。

接着就是InstanceResource,该接口提供的是服务的续约请求已经服务的剔除请求:

服务续约请求接口:renewLease

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第18张图片

 这里通过服务名和id最终调用的是AbstractInstanceRegistry.renew:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第19张图片

从服务列表registry里面获取对应lease,然后调用对应的renew()方法进行时间的更新:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第20张图片

这样就完成了服务的续约操作,也就是将服务的更新时间延长一定时间。

接着就是进行服务的剔除接口操作

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第21张图片

通过服务名及i最终调用的是AbstractInstanceRegistry.cancal :

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第22张图片

接着调用internalCancel:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第23张图片

获取到对应的instanceInfo然后将其从registry进行remove掉,然后获取的lease调用cancel()给了个过期时间:

深入理解SpringCloud源码探究篇 | Eureka服务端源码分析_第24张图片

以上是客户端主动请求剔除操作,还有一个专门的定时任务进行服务的轮询对比过期时间的剔除操作,同样的逻辑,这里就不在赘述了

 

总结

eureka服务服务端通过jersey对外提供服务注册和服务获取以及服务续约和剔除等接口,服务信息被注册放入到一个名为registry的ConcurrentHashMap里。

 

以上就是本章eureka服务端源码分析的所有内容,如有什么不对的地方望指出。感谢你的收看,下章将进行eureka客户端源码的探究,如有兴趣记得关注哦。

 

 

你可能感兴趣的:(springcloud)