Eureka源碼閱讀解析Server服務(wù)端啟動(dòng)流程實(shí)例
環(huán)境
- eureka版本:1.10.11
- Spring Cloud : 2020.0.2
- Spring Boot :2.4.4
測(cè)試demo代碼:github.com/hsfxuebao/s…
本文主要看看spring cloud是怎樣自動(dòng)裝配eureka server 并啟動(dòng)eureka server的并解析其關(guān)鍵源碼。首先我們會(huì)配置啟動(dòng)一個(gè)spring cloud eureka server 服務(wù),接著看看是spring cloud怎樣自動(dòng)裝配eureka的,并看看一些核心組件的創(chuàng)建源碼,最后解析下eureka server 啟動(dòng)初始化流程,看看都干了些啥東西
1.spring cloud整合eureka server demo
1.1 新建spring boot項(xiàng)目
pom.xml文件添加
用來(lái)規(guī)范spring cloud 的版本:
<dependencyManagement>
<!--引入springcloud依賴的-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2020.0.2E</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
添加用到的依賴:
<dependencies>
<!--web依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<!--unit test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--spring cloud eureka server 依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
配置文件
eureka:
instance:
hostname: localhost
client:
service-url: # eureka server 的地址, 咱們單實(shí)例模式就寫自己好了
defaultZone: http://localhost:7000/eureka
register-with-eureka: false # 不向eureka server 注冊(cè)自己
fetch-registry: false # 不向eureka server 獲取服務(wù)列表
1.2 啟動(dòng)類
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer {
public static void main(String[] args) {
SpringApplication.run(EurekaServer.class, args);
}
}
添加@EnableEurekaServer注解,表示它是個(gè)eureka server。
1.3 啟動(dòng)
訪問(wèn)地址:http://localhost:7000/

注意:由于是源碼解析的文章,更詳細(xì)的配置可以查看github.com/hsfxuebao/s…
2. spring cloud自動(dòng)裝配eureka server源碼解析
2.1 @EnableEurekaServer注解
上一節(jié)配置eureka server的時(shí)候我們?cè)谂渲妙惿霞恿藗€(gè)@EnableEurekaServer注解,表示啟動(dòng)一個(gè)eureka server 。 我們看看這個(gè)注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EurekaServerMarkerConfiguration.class)
public @interface EnableEurekaServer {
}
上面有個(gè)@Import(EurekaServerMarkerConfiguration.class) 注解導(dǎo)入了EurekaServerMarkerConfiguration配置類,我們看下配置類:
@Configuration
public class EurekaServerMarkerConfiguration {
@Bean
public Marker eurekaServerMarkerBean() {
return new Marker();
}
class Marker {
}
}
就是創(chuàng)建了一個(gè)EurekaServerMarkerConfiguration.Marker 對(duì)象,交給spring保管,一看就是個(gè)標(biāo)記,標(biāo)識(shí),僅僅是個(gè)標(biāo)識(shí)。
2.2 EurekaServerAutoConfiguration
2.2.1 查找starter 自動(dòng)裝配類的技巧
spring boot的starter基本都會(huì)自動(dòng)裝配類,也就是AutoConfiguration 結(jié)尾的類,如果我們找不到某個(gè)starter的自動(dòng)裝配類是那個(gè),可以去starter對(duì)應(yīng)jar 包里面META-INF 文件夾下面找spring.factories (這是spring spi 配置文件)文件。比如說(shuō)我可以在spring-cloud-netflix-eureka-server 這個(gè)項(xiàng)目下找到META-INF 文件夾下面找spring.factories文件。

文件內(nèi)容就是上圖里面的,可以看到自動(dòng)裝配類就是EurekaServerAutoConfiguration。
2.2.2 EurekaServerAutoConfiguration源碼解析
首先,看看 EurekaServerAutoConfiguration 自動(dòng)配置類里面都干了啥。
@Configuration
@Import(EurekaServerInitializerConfiguration.class)
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
@EnableConfigurationProperties({ EurekaDashboardProperties.class,
InstanceRegistryProperties.class })
@PropertySource("classpath:/eureka/server.properties")
public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter{}
先看看類上面聲明的這一堆注解:
@Import(EurekaServerInitializerConfiguration.class): 導(dǎo)入(裝配)配置類EurekaServerInitializerConfiguration,這個(gè)我們后面看下,屬于初始化流程。@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)就是是否存在EurekaServerMarkerConfiguration.Marker類的bean實(shí)例,這個(gè)肯定存在的,我們?cè)?code>@EnableEurekaServer 注解中就創(chuàng)建了這么一個(gè)bean 交給spring 管理了。存在就會(huì)往下走,不存在就拉倒了,不會(huì)再加載配置類里面別的東西了,也就是不會(huì)自動(dòng)啟動(dòng)eureka server了。@EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class })這個(gè)就是裝配這兩個(gè)配置類,一個(gè)是關(guān)于Dashboard 的,一個(gè)是關(guān)于instance 的配置,也就是eureka server的配置, 就是將我們寫在application.yml配置文件中關(guān)于eureka 的配置set到這里面的屬性中。@PropertySource(“classpath:/eureka/server.properties”)加載/eureka/server.properties配置文件,這個(gè)沒(méi)啥意思。
然后,看看里面成員有哪些。
@Autowired private ApplicationInfoManager applicationInfoManager; @Autowired private EurekaServerConfig eurekaServerConfig; @Autowired private EurekaClientConfig eurekaClientConfig; @Autowired private EurekaClient eurekaClient; @Autowired private InstanceRegistryProperties instanceRegistryProperties;
ApplicationInfoManager / EurekaClientConfig / EurekaClient 這幾個(gè)bean 一看就是eureka client 里面的,我們這里是eureka server ,為啥能夠注入進(jìn)來(lái)呢?
- 原因是 eureka server 的starter 里面依賴了eureka client starter,eureka client starter自動(dòng)裝配的這些實(shí)例bean 。有些小伙伴可能會(huì)有疑問(wèn),我啟用(自動(dòng)裝配)eureka client,不需要在配置類上面添加
@EnableEurekaClient注解嘛。其實(shí)從spring cloud netflix 1.4版本往后主要引入了這個(gè) eureka client starter 依賴,就會(huì)自動(dòng)裝配,不需要添加@EnableEurekaClient注解也是可以的。
接著,看看創(chuàng)建了哪些核心組件
dashboard 的controller
@Bean
@ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true)
public EurekaController eurekaController() {
return new EurekaController(this.applicationInfoManager);
}
注冊(cè)表創(chuàng)建
@Bean
public PeerAwareInstanceRegistry peerAwareInstanceRegistry(
ServerCodecs serverCodecs) {
this.eurekaClient.getApplications(); // force initialization
return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig,
serverCodecs, this.eurekaClient,
this.instanceRegistryProperties.getExpectedNumberOfClientsSendingRenews(),
this.instanceRegistryProperties.getDefaultOpenForTrafficCount());
}
注冊(cè)表,就是存放我們注冊(cè)的實(shí)例信息的,這個(gè)是個(gè)非常核心的組件。這里直接創(chuàng)建了一個(gè)InstanceRegistry 對(duì)象,這個(gè)InstanceRegistry繼承eureka server 里面PeerAwareInstanceRegistryImpl 類。
集群節(jié)點(diǎn)信息類對(duì)象
@Bean
@ConditionalOnMissingBean
public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry,
ServerCodecs serverCodecs) {
return new RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig,
this.eurekaClientConfig, serverCodecs, this.applicationInfoManager);
}
PeerEurekaNodes 這個(gè)類,從名字上也能看出來(lái)是集群節(jié)點(diǎn)的類,而且是Nodes ,表示多個(gè)節(jié)點(diǎn),其實(shí)里面就是封裝eureka server 集群的節(jié)點(diǎn)們。這里是創(chuàng)建RefreshablePeerEurekaNodes 對(duì)象,RefreshablePeerEurekaNodes繼承PeerEurekaNodes 類,實(shí)現(xiàn)spring 的ApplicationListener 事件監(jiān)聽接口,自然而然的RefreshablePeerEurekaNodes類具有了刷新集群節(jié)點(diǎn)信息功能(能力)。
EurekaServerContext
@Bean
public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,
PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) {
return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs,
registry, peerEurekaNodes, this.applicationInfoManager);
}
EurekaServerContext 從字面上是eureka server 上下文,其實(shí)就是eureka server 啟動(dòng)的時(shí)候會(huì)初始化PeerEurekaNodes 與PeerAwareInstanceRegistry 注冊(cè)表,銷毀的是否停止這2個(gè)組件
EurekaServerBootstrap
@Bean
public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,
EurekaServerContext serverContext) {
return new EurekaServerBootstrap(this.applicationInfoManager,
this.eurekaClientConfig, this.eurekaServerConfig, registry,
serverContext);
}
一般叫Bootstrap 的類都是那種掌管項(xiàng)目啟動(dòng)與停止的,EurekaServerBootstrap 也不例外,它里面就有contextInitialized 項(xiàng)目啟動(dòng)與contextDestroyed項(xiàng)目停止/銷毀的方法。
jersey框架 關(guān)于jersey框架的東西,eureka server 對(duì)外暴露rest ful接口,使用的框架就是jersey(這玩意國(guó)內(nèi)很少用),作用/定位就跟我們常用的springmvc 框架差不多。
3. eureka server 初始化源碼解析
3.1 EurekaServerInitializerConfiguration
第2小節(jié)介紹 spring cloud eureka server 啟動(dòng)的時(shí)候自動(dòng)裝配的一些組件,本小節(jié)就看下eureka server的初始化流程。
在自動(dòng)裝配類EurekaServerAutoConfiguration 類上面聲明了@Import(EurekaServerInitializerConfiguration.class) ,我們介紹說(shuō)是導(dǎo)入(加載)EurekaServerInitializerConfiguration 這個(gè)配置,一看這個(gè)類名字就是eureka server 初始化用的。
@Configuration
public class EurekaServerInitializerConfiguration
implements ServletContextAware, SmartLifecycle, Ordered {
}
@Configuration是個(gè)配置類,實(shí)現(xiàn)ServletContextAware,SmartLifecycle,Ordered 接口:
ServletContextAware作用是自動(dòng)注入ServletContext實(shí)例。SmartLifecycle接口 屬于spring 聲明周期的,start 方法執(zhí)行時(shí)機(jī)是,當(dāng)spring 的bean都實(shí)例化,初始化完事后,會(huì)調(diào)用SmartLifecycle 的start方法,isAutoStartup 方法返回的true 或者false 決定要不要執(zhí)行start方法,這里isAutoStartup方法返回的true。- stop 方法就是項(xiàng)目停止,容器銷毀的時(shí)候會(huì)調(diào)用。
先來(lái)看下start 方法干了啥
@Override
public void start() {
new Thread(new Runnable() {
@Override
public void run() {
try {
//TODO: is this class even needed now?
eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
log.info("Started Eureka Server");
publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
EurekaServerInitializerConfiguration.this.running = true;
publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
}
catch (Exception ex) {
// Help!
log.error("Could not initialize Eureka servlet context", ex);
}
}
}).start();
}
創(chuàng)建了一個(gè)線程,先是執(zhí)行eurekaServerBootstrap 的contextInitialized 初始化方法。接著就是發(fā)布 EurekaRegistryAvailableEvent 事件,設(shè)置running 為true ,最后就是發(fā)布EurekaServerStartedEvent 事件。 這里我們只關(guān)心eurekaServerBootstrap的contextInitialized 方法。
public void contextInitialized(ServletContext context) {
initEurekaEnvironment();
initEurekaServerContext();
context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
}
初始化eureka environment, 接著初始化context,最后是將context塞到 ServletContext的屬性中。 initEurekaEnvironment這個(gè)我們就不看了。主要看下initEurekaServerContext 方法:
if (isAws(this.applicationInfoManager.getInfo())) {
this.awsBinder = new AwsBinderDelegate(this.eurekaServerConfig,
this.eurekaClientConfig, this.registry, this.applicationInfoManager);
this.awsBinder.start();
}
EurekaServerContextHolder.initialize(this.serverContext);
log.info("Initialized server context");
// Copy registry from neighboring eureka node
int registryCount = this.registry.syncUp();
this.registry.openForTraffic(this.applicationInfoManager, registryCount);
// Register all monitoring statistics.
EurekaMonitors.registerAllStats();
isAws 是亞馬遜云環(huán)境的時(shí)候執(zhí)行if里面的那一堆,這個(gè)不看了。
EurekaServerContextHolder.initialize(this.serverContext);這行代碼沒(méi)干啥。
int registryCount = this.registry.syncUp(); this.registry.openForTraffic(this.applicationInfoManager, registryCount);
registry.syncUp()這個(gè)就是去集群中的其他節(jié)點(diǎn)拉取注冊(cè)表。下篇文章分析 registry.openForTraffic()這個(gè)是Server端定時(shí)清理過(guò)期的Client。以后在詳細(xì)分析。
3.2 DefaultEurekaServerContext
我們?cè)诮榻B自動(dòng)裝配類EurekaServerAutoConfiguration 裝配組件的時(shí)候,介紹過(guò)EurekaServerContext ,說(shuō)他字面上是eureka server 上下文,其實(shí)就是eureka server 啟動(dòng)的時(shí)候會(huì)初始化PeerEurekaNodes 與PeerAwareInstanceRegistry 注冊(cè)表,銷毀的是否停止這2個(gè)組件 我們來(lái)看下 @PostConstruct 注解修飾的initialize 方法
@PostConstruct
public void initialize() {
this.peerEurekaNodes.start();
this.registry.init(this.peerEurekaNodes);
}
干了2件事,啟動(dòng)peerEurekaNodes ,初始化注冊(cè)表。 peerEurekaNodes#start:
public void start() {
updatePeerEurekaNodes(resolvePeerUrls());
Runnable peersUpdateTask = new Runnable() {
@Override
public void run() {
updatePeerEurekaNodes(resolvePeerUrls());
}
};
taskExecutor.scheduleWithFixedDelay(
peersUpdateTask,
serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
serverConfig.getPeerEurekaNodesUpdateIntervalMs(),
TimeUnit.MILLISECONDS
);
}
先是更新集群節(jié)點(diǎn)信息,就是創(chuàng)建節(jié)點(diǎn)對(duì)象。
接著就是創(chuàng)建一個(gè)定時(shí)任務(wù)更新,默認(rèn)是10分鐘。
注冊(cè)表初始化:
@Override
public void init(PeerEurekaNodes peerEurekaNodes) throws Exception {
this.numberOfReplicationsLastMin.start();
this.peerEurekaNodes = peerEurekaNodes;
initializedResponseCache();
scheduleRenewalThresholdUpdateTask();
initRemoteRegionRegistry();
}
numberOfReplicationsLastMin這是記錄續(xù)約次數(shù)的一個(gè)組件,用在服務(wù)剔除。initializedResponseCache初始化響應(yīng)cache ,這個(gè)其實(shí)就是 服務(wù)發(fā)現(xiàn)的時(shí)候三級(jí)緩存。
參考
springcloud-source-study學(xué)習(xí)github地址
以上就是Eureka源碼閱讀解析Server服務(wù)端啟動(dòng)流程實(shí)例的詳細(xì)內(nèi)容,更多關(guān)于Eureka Server服務(wù)端啟動(dòng)流程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Eureka源碼解析服務(wù)離線狀態(tài)變更
- Eureka源碼閱讀Client啟動(dòng)入口注冊(cè)續(xù)約及定時(shí)任務(wù)
- Eureka源碼核心類預(yù)備知識(shí)
- Eureka源碼閱讀之環(huán)境搭建及工程結(jié)構(gòu)
- SpringCloud?eureka(server)微服務(wù)集群搭建過(guò)程
- spring cloud-給Eureka Server加上安全的用戶認(rèn)證詳解
- spring-cloud入門之eureka-server(服務(wù)發(fā)現(xiàn))
- spring cloud將spring boot服務(wù)注冊(cè)到Eureka Server上的方法
相關(guān)文章
Java生產(chǎn)者和消費(fèi)者例子_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
生產(chǎn)者-消費(fèi)者(producer-consumer)問(wèn)題,也稱作有界緩沖區(qū)(bounded-buffer)問(wèn)題,兩個(gè)進(jìn)程共享一個(gè)公共的固定大小的緩沖區(qū)。下文通過(guò)實(shí)例給大家介紹java生產(chǎn)者和消費(fèi)者,感興趣的朋友一起學(xué)習(xí)吧2017-05-05
java學(xué)生信息管理系統(tǒng)設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了java學(xué)生信息管理系統(tǒng)設(shè)計(jì),學(xué)生信息添加進(jìn)入數(shù)據(jù)庫(kù)的事務(wù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
Java中Word與PDF轉(zhuǎn)換為圖片的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)將Word與PDF轉(zhuǎn)換為圖片,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-10-10
如何通過(guò)一張圖搞懂springBoot自動(dòng)注入原理
這篇文章主要給大家介紹了關(guān)于如何通過(guò)一張圖搞懂springBoot自動(dòng)注入原理的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-02-02
詳解Java?SSM項(xiàng)目部署上線配置方法(阿里云服務(wù)器ECS?+?云數(shù)據(jù)庫(kù)RDS?MySQL)(寶塔)
這篇文章主要介紹了Java?SSM項(xiàng)目部署上線(阿里云服務(wù)器ECS?+?云數(shù)據(jù)庫(kù)RDS?MySQL)(寶塔)的圖文教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2024-01-01
手把手帶你了解Java-Stream流方法學(xué)習(xí)及總結(jié)
這篇文章主要介紹了通過(guò)實(shí)例了解JavaStream流的方法學(xué)習(xí)和總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-08-08

