1. 程式人生 > >Eureka Server啟動過程分析

Eureka Server啟動過程分析

**1.首先**,SpringCloud充分利用了SpringBoot的自動裝配特點 eureka-server的jar包,發現在META-INF下面的配置檔案spring.factories,裡面記錄了Spring Boot啟動的時候會載入EurekaServerAutoConfiguration自動配置類 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173132547-1385081589.png) **2.其次**,分析EurekaServerAutoConfiguration類的原始碼,我們發現該類的類頭中存在@ConditionalOnBean的註解,如圖 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173152807-166356799.png) 他代表的意思是,如果想要裝配EurekaServerAutoConfigration,Spring容器中必須要有一個Marker的類的例項。 EurekaServerMarkerConfigration.Marker類: ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173159617-1301347380.png) 我們通過Find Usages功能查詢,在什麼樣的情況下,我們會向Spring容器中注入這個Marker物件 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173209207-1733937793.png) 我們發現,如果在Spring Cloud啟動過程中新增@EnableEurekaServer註解,我們就會向容器中新增這個Marker的例項物件。也就是說,@EnableEurekaServer註解是Spring Cloud自動載入EurekaServerAutoConfiguration的控制開關。 **3.再次**,我們需要研究載入EurekaServerAutoConfigration類後,會向容器中注入那些Bean,有那些操作 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173216587-1350968842.png) 通過structure結構圖,我們發現,EurekaServer類有一些自動逸的Codec實現,PeerEurekaNodes的回撥介面。但是主要的,與EurekaServer啟動相關的Bean有6個:EurekaController、PeerAuareInstanceRegistry、PeerEurekaNodes、EurekaServerContext、EurekaServerBootstrap、FilterRegistationBean。 **3.1** EurekaController ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173223079-2138180883.png) 注入一個對外的介面——儀表盤/後臺介面,EurekaController。可以在配置檔案中關閉它,但是預設是開啟的狀態。eureka.dashboard.enabled=true **3.2** PeerAuareInstanceRegistry 和 PeerEurekaNodes ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173230432-77307812.png) PeerAwareInstanceRegistry是一個對等節點感知例項註冊器(叢集模式下注冊服務使用到的註冊器)。並且值得注意的是,EurekaServer叢集模式中各個節點是對等的,沒有主從之分。(這一點和Zookeeper不一樣,zk通過ZAB協議實現了分散式一致性,但是EurekaServer並沒有實現任何分散式演算法) PeerEurekaNodes是用來輔助封裝對等節點相關的資訊和操作,比如更新叢集中的對等節點。 這裡我們稍微看下RefreshablePeerEurekaNodes的原始碼,我們發現它是在繼承PeerEurekaNodes的基礎上實現了ApplicationListener介面,該介面只定義了一個回撥方法,處理事件的回撥 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173241548-2054771193.png) ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173245998-958762964.png) 實際上,例項化RefreshablePeerEurekaNodes物件還是通過父類的構造方法完成的,這個在程式碼的200行中有體現。 **3.3 **EurekaServerContext ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173253947-1284252737.png) 向容器中注入了EurekaServerContext的物件,具體為DefaultEurekaServerContext。翻閱DefaultEurekaServerContext原始碼中,我們發現它通過Spring的@PostConstruct註解呼叫了peerEurekaNodes物件的start()方法 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173259257-192866630.png) 具體在看一下64行呼叫的peerEurekaNodes.start()方法做了哪些操作 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173313499-1692281840.png) 首先,定義了一個執行緒池Eureka-PeerNodesUpdater——Eureka的更新對等節點執行緒,最終start方法會開啟這個執行緒,不停呼叫93行所指向的updatePeerEurekaNodes()方法。 這個updatePeerEurekaNodes()方法會更新對等節點資訊,因為EurekaServer節點可能會不斷的變化(比如,Eureka叢集中某個節點的上下線) 而updatePeerEurekaNodes()方法主要做了什麼呢? ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173320544-1350573746.png) 其實就是Removing no longer available peer nodes和Adding new peer nodes。 至此,總結一下,EurekaServerContext的例項化過程,會啟動更新遠端對等節點的執行緒,不時的重新整理遠端對等節點的資訊。 **3.4** EurekaServerBootstrap ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173325912-1360883735.png) 注入EurekaServerBootstrap物件,後續的EurekaServer應用的啟動要依靠這個物件 **3.5** FilterRegistrationBean ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173332183-405456740.png) 在Jersey框架下新增一個攔截器ServletContainer物件,攔截所有的/eureka/*的請求,是的Jersey框架開始管理所有的/eureka/*的請求 **4.**分析完EurekaServerAutoConfiguration具體注入哪些事情後,我們在返回EurekaServerAutoConfiguration的類頭分析 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173341907-1385293981.png) 它利用的Spring的@Import註解,在EurekaServerAutoConfigration注入完所有的Bean後,再次呼叫了EurekaServerInitializerConfigration物件,裝配了它。 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173346552-1591762111.png) 由於EurekaServerInitializerConfiguration實現了SmartLifecycle介面,所有Spring容器的Bean建立完成後會回撥start()方法。(順便說一下,EurekaServerInitializerConfiguration類沒有顯式的無參方法,所以它的初始化會呼叫預設的無參構造方法,且幾乎不會做什麼操作) ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173355349-615431667.png) 而start()方法會開啟一個後臺執行緒去使用eurekaServerBootstrap物件初始化Context。 **4.1** 分析eurekaServerBootstrap物件的contextInitialized()方法(在3.4步驟時例項化的) ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173400364-490690313.png) 初始化上下文實際上就是初始化環境變數方法的呼叫和初始化EurekaServerContext()方法。其中initEurekaEnvironment()方法就是讀取配置,如果沒有配置則設定成預設配置 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173413986-1470846051.png) 再看看initEurekaServerContext()方法 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173418683-476516475.png) 這個方法中大體分為5步,1.註冊序列化的轉化器;2.對aws的情況進行特殊處理;3.為非IOC容器提供獲取serverContext物件介面;4.從其他註冊中心複製註冊新資訊;5.改變EurekaServer的狀態,EurekaServer啟動完成的標誌 這裡值得關注的是步驟4,如何複製其他節點的註冊資訊到本EurekaServer上。 **4.2** registry.syncUp()方法 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173424836-1956308501.png) 這裡224行的register()方法是做把遠端獲得過來的註冊資訊註冊到自己的登錄檔中(map中) ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173430054-1130195115.png) register()方法中具體就是在保證執行緒安全的情況下對registry物件進行操作 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173436546-1448242872.png) 綜上所述,registry.syncUp()方法就是拷貝其他對等節點的註冊資訊到自己的登錄檔map中 **4.3** registry.openForTraffic()方法 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173442905-279079899.png) 這裡,我們肯定選擇Peer的實現,因為Eureka Server的啟動一般都是叢集模式 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173449123-455349796.png) openForTraffic()方法裡,具體就是設定例項狀態為UP,並呼叫父類的postInit()方法 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173455269-1617644313.png) 在com.netflix.eureka.registry.AbstractInstanceRegistry#postInit()方法中,主要是啟動失效剔除定時任務的,具體的任務邏輯在EvicationTask中定義。 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173459856-1864121823.png) 這裡呼叫了 AbstractInstanceRegistry的evict()方法 ![](https://img2020.cnblogs.com/blog/937573/202101/937573-20210103173505365-38085481.png) 這個方法就是根據失效時常剔除失效的服務 **綜上所屬,registry.syncUp()就是開啟一個服務失效剔除執行緒** **所以,** **Eureka Server啟動過程就是在@EnableEurekaServer開關的基礎上,建立了一些後臺程序去同步註冊資訊,併發佈一個Jersey的web服務。它充分利用了Spring Boot的自動裝配功能和spring的一些回撥介面實