14

Eureka Server启动过程分析

 3 years ago
source link: http://www.cnblogs.com/angel-of-death/p/14226260.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1.首先,SpringCloud充分利用了SpringBoot的自动装配特点

eureka-server的jar包,发现在META-INF下面的配置文件spring.factories,里面记录了Spring Boot启动的时候会加载EurekaServerAutoConfiguration自动配置类

A73MJzA.png!mobile

2.其次,分析EurekaServerAutoConfiguration类的源码,我们发现该类的类头中存在@ConditionalOnBean的注解,如图

Avu2yqI.png!mobile

他代表的意思是,如果想要装配EurekaServerAutoConfigration,Spring容器中必须要有一个Marker的类的实例。

EurekaServerMarkerConfigration.Marker类:

JbEz6nb.png!mobile

我们通过Find Usages功能查询,在什么样的情况下,我们会向Spring容器中注入这个Marker对象

3q6RNzI.png!mobile

我们发现,如果在Spring Cloud启动过程中添加@EnableEurekaServer注解,我们就会向容器中添加这个Marker的实例对象。也就是说,@EnableEurekaServer注解是Spring Cloud自动加载EurekaServerAutoConfiguration的控制开关。

3.再次,我们需要研究加载EurekaServerAutoConfigration类后,会向容器中注入那些Bean,有那些操作

FFbAvqu.png!mobile

通过structure结构图,我们发现,EurekaServer类有一些自动逸的Codec实现,PeerEurekaNodes的回调接口。但是主要的,与EurekaServer启动相关的Bean有6个:EurekaController、PeerAuareInstanceRegistry、PeerEurekaNodes、EurekaServerContext、EurekaServerBootstrap、FilterRegistationBean。

3.1EurekaController

6R3mUrb.png!mobile

注入一个对外的接口——仪表盘/后台界面,EurekaController。可以在配置文件中关闭它,但是默认是开启的状态。eureka.dashboard.enabled=true

3.2PeerAuareInstanceRegistry 和 PeerEurekaNodes

AziymiN.png!mobile

PeerAwareInstanceRegistry是一个对等节点感知实例注册器(集群模式下注册服务使用到的注册器)。并且值得注意的是,EurekaServer集群模式中各个节点是对等的,没有主从之分。(这一点和Zookeeper不一样,zk通过ZAB协议实现了分布式一致性,但是EurekaServer并没有实现任何分布式算法)

PeerEurekaNodes是用来辅助封装对等节点相关的信息和操作,比如更新集群中的对等节点。

这里我们稍微看下RefreshablePeerEurekaNodes的源码,我们发现它是在继承PeerEurekaNodes的基础上实现了ApplicationListener接口,该接口只定义了一个回调方法,处理事件的回调

RNzEZfY.png!mobile6FzmAbJ.png!mobile

实际上,实例化RefreshablePeerEurekaNodes对象还是通过父类的构造方法完成的,这个在代码的200行中有体现。

**3.3 **EurekaServerContext

n2ie2mm.png!mobile

向容器中注入了EurekaServerContext的对象,具体为DefaultEurekaServerContext。翻阅DefaultEurekaServerContext源码中,我们发现它通过Spring的@PostConstruct注解调用了peerEurekaNodes对象的start()方法

JRRNfuv.png!mobile

具体在看一下64行调用的peerEurekaNodes.start()方法做了哪些操作

Nf2eYvf.png!mobile

首先,定义了一个线程池Eureka-PeerNodesUpdater——Eureka的更新对等节点线程,最终start方法会开启这个线程,不停调用93行所指向的updatePeerEurekaNodes()方法。

这个updatePeerEurekaNodes()方法会更新对等节点信息,因为EurekaServer节点可能会不断的变化(比如,Eureka集群中某个节点的上下线)

而updatePeerEurekaNodes()方法主要做了什么呢?

E7NzE3M.png!mobile

其实就是Removing no longer available peer nodes和Adding new peer nodes。

至此,总结一下,EurekaServerContext的实例化过程,会启动更新远程对等节点的线程,不时的刷新远程对等节点的信息。

3.4EurekaServerBootstrap

v26nMvE.png!mobile

注入EurekaServerBootstrap对象,后续的EurekaServer应用的启动要依靠这个对象

3.5FilterRegistrationBean

reQZjuV.png!mobile

在Jersey框架下添加一个拦截器ServletContainer对象,拦截所有的/eureka/ 的请求,是的Jersey框架开始管理所有的/eureka/ 的请求

4.分析完EurekaServerAutoConfiguration具体注入哪些事情后,我们在返回EurekaServerAutoConfiguration的类头分析

6ZNvI3q.png!mobile

它利用的Spring的@Import注解,在EurekaServerAutoConfigration注入完所有的Bean后,再次调用了EurekaServerInitializerConfigration对象,装配了它。

NVbeQr.png!mobile

由于EurekaServerInitializerConfiguration实现了SmartLifecycle接口,所有Spring容器的Bean创建完成后会回调start()方法。(顺便说一下,EurekaServerInitializerConfiguration类没有显式的无参方法,所以它的初始化会调用默认的无参构造方法,且几乎不会做什么操作)

nuA7fu6.png!mobile

而start()方法会开启一个后台线程去使用eurekaServerBootstrap对象初始化Context。

4.1分析eurekaServerBootstrap对象的contextInitialized()方法(在3.4步骤时实例化的)

iAfYVnY.png!mobile

初始化上下文实际上就是初始化环境变量方法的调用和初始化EurekaServerContext()方法。其中initEurekaEnvironment()方法就是读取配置,如果没有配置则设置成默认配置

7viQruz.png!mobile

再看看initEurekaServerContext()方法

rQFRJbq.png!mobile

这个方法中大体分为5步,1.注册序列化的转化器;2.对aws的情况进行特殊处理;3.为非IOC容器提供获取serverContext对象接口;4.从其他注册中心复制注册新信息;5.改变EurekaServer的状态,EurekaServer启动完成的标志

这里值得关注的是步骤4,如何复制其他节点的注册信息到本EurekaServer上。

4.2registry.syncUp()方法

VvqQbe.png!mobile

这里224行的register()方法是做把远程获得过来的注册信息注册到自己的注册表中(map中)

7zQRraM.png!mobile

register()方法中具体就是在保证线程安全的情况下对registry对象进行操作

NVzMFvE.png!mobile

综上所述,registry.syncUp()方法就是拷贝其他对等节点的注册信息到自己的注册表map中

4.3registry.openForTraffic()方法

ZrQryya.png!mobile

这里,我们肯定选择Peer的实现,因为Eureka Server的启动一般都是集群模式

aQniiye.png!mobile

openForTraffic()方法里,具体就是设置实例状态为UP,并调用父类的postInit()方法

JBVfeen.png!mobile

在com.netflix.eureka.registry.AbstractInstanceRegistry#postInit()方法中,主要是启动失效剔除定时任务的,具体的任务逻辑在EvicationTask中定义。

eYjQBz6.png!mobile

这里调用了 AbstractInstanceRegistry的evict()方法

YRF3Af6.png!mobile

这个方法就是根据失效时常剔除失效的服务

综上所属,registry.syncUp()就是开启一个服务失效剔除线程

所以,

Eureka Server启动过程就是在@EnableEurekaServer开关的基础上,创建了一些后台进程去同步注册信息,并发布一个Jersey的web服务。它充分利用了Spring Boot的自动装配功能和spring的一些回调接口实现。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK