Eureka源碼閱讀解析Server服務端啟動流程實例
環(huán)境
- eureka版本:1.10.11
- Spring Cloud : 2020.0.2
- Spring Boot :2.4.4
測試demo代碼:github.com/hsfxuebao/s…
本文主要看看spring cloud是怎樣自動裝配eureka server
并啟動eureka server
的并解析其關鍵源碼。首先我們會配置啟動一個spring cloud eureka server
服務,接著看看是spring cloud
怎樣自動裝配eureka的,并看看一些核心組件的創(chuàng)建源碼,最后解析下eureka server
啟動初始化流程,看看都干了些啥東西
1.spring cloud整合eureka server demo
1.1 新建spring boot項目
pom.xml文件添加
用來規(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 的地址, 咱們單實例模式就寫自己好了 defaultZone: http://localhost:7000/eureka register-with-eureka: false # 不向eureka server 注冊自己 fetch-registry: false # 不向eureka server 獲取服務列表
1.2 啟動類
@SpringBootApplication @EnableEurekaServer public class EurekaServer { public static void main(String[] args) { SpringApplication.run(EurekaServer.class, args); } }
添加@EnableEurekaServer
注解,表示它是個eureka server
。
1.3 啟動
訪問地址:http://localhost:7000/
注意:由于是源碼解析的文章,更詳細的配置可以查看github.com/hsfxuebao/s…
2. spring cloud自動裝配eureka server源碼解析
2.1 @EnableEurekaServer注解
上一節(jié)配置eureka server的時候我們在配置類上加了個@EnableEurekaServer
注解,表示啟動一個eureka server
。 我們看看這個注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(EurekaServerMarkerConfiguration.class) public @interface EnableEurekaServer { }
上面有個@Import(EurekaServerMarkerConfiguration.class)
注解導入了EurekaServerMarkerConfiguration
配置類,我們看下配置類:
@Configuration public class EurekaServerMarkerConfiguration { @Bean public Marker eurekaServerMarkerBean() { return new Marker(); } class Marker { } }
就是創(chuàng)建了一個EurekaServerMarkerConfiguration.Marker
對象,交給spring保管,一看就是個標記,標識,僅僅是個標識。
2.2 EurekaServerAutoConfiguration
2.2.1 查找starter 自動裝配類的技巧
spring boot的starter
基本都會自動裝配類,也就是AutoConfiguration
結尾的類,如果我們找不到某個starter的自動裝配類是那個,可以去starter對應jar
包里面META-INF
文件夾下面找spring.factories
(這是spring spi 配置文件)文件。比如說我可以在spring-cloud-netflix-eureka-server
這個項目下找到META-INF
文件夾下面找spring.factories
文件。
文件內容就是上圖里面的,可以看到自動裝配類就是EurekaServerAutoConfiguration
。
2.2.2 EurekaServerAutoConfiguration源碼解析
首先,看看 EurekaServerAutoConfiguration
自動配置類里面都干了啥。
@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)
: 導入(裝配)配置類EurekaServerInitializerConfiguration,這個我們后面看下,屬于初始化流程。@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
就是是否存在EurekaServerMarkerConfiguration.Marker
類的bean實例,這個肯定存在的,我們在@EnableEurekaServer
注解中就創(chuàng)建了這么一個bean 交給spring 管理了。存在就會往下走,不存在就拉倒了,不會再加載配置類里面別的東西了,也就是不會自動啟動eureka server了。@EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class })
這個就是裝配這兩個配置類,一個是關于Dashboard 的,一個是關于instance 的配置,也就是eureka server的配置, 就是將我們寫在application.yml配置文件中關于eureka 的配置set到這里面的屬性中。@PropertySource(“classpath:/eureka/server.properties”)
加載/eureka/server.properties
配置文件,這個沒啥意思。
然后,看看里面成員有哪些。
@Autowired private ApplicationInfoManager applicationInfoManager; @Autowired private EurekaServerConfig eurekaServerConfig; @Autowired private EurekaClientConfig eurekaClientConfig; @Autowired private EurekaClient eurekaClient; @Autowired private InstanceRegistryProperties instanceRegistryProperties;
ApplicationInfoManager / EurekaClientConfig / EurekaClient
這幾個bean 一看就是eureka client 里面的,我們這里是eureka server ,為啥能夠注入進來呢?
- 原因是 eureka server 的starter 里面依賴了eureka client starter,eureka client starter自動裝配的這些實例bean 。有些小伙伴可能會有疑問,我啟用(自動裝配)eureka client,不需要在配置類上面添加
@EnableEurekaClient
注解嘛。其實從spring cloud netflix 1.4
版本往后主要引入了這個 eureka client starter 依賴,就會自動裝配,不需要添加@EnableEurekaClient
注解也是可以的。
接著,看看創(chuàng)建了哪些核心組件
dashboard 的controller
@Bean @ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true) public EurekaController eurekaController() { return new EurekaController(this.applicationInfoManager); }
注冊表創(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()); }
注冊表,就是存放我們注冊的實例信息的
,這個是個非常核心的組件
。這里直接創(chuàng)建了一個InstanceRegistry
對象,這個InstanceRegistry
繼承eureka server 里面PeerAwareInstanceRegistryImpl
類。
集群節(jié)點信息類對象
@Bean @ConditionalOnMissingBean public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry, ServerCodecs serverCodecs) { return new RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.applicationInfoManager); }
PeerEurekaNodes
這個類,從名字上也能看出來是集群節(jié)點的類,而且是Nodes
,表示多個節(jié)點,其實里面就是封裝eureka server 集群的節(jié)點們。這里是創(chuàng)建RefreshablePeerEurekaNodes
對象,RefreshablePeerEurekaNodes
繼承PeerEurekaNodes
類,實現(xiàn)spring 的ApplicationListene
r 事件監(jiān)聽接口,自然而然的RefreshablePeerEurekaNodes類具有了刷新集群節(jié)點信息功能(能力)。
EurekaServerContext
@Bean public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs, PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) { return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs, registry, peerEurekaNodes, this.applicationInfoManager); }
EurekaServerContext
從字面上是eureka server 上下文,其實就是eureka server 啟動的時候會初始化PeerEurekaNodes
與PeerAwareInstanceRegistry
注冊表,銷毀的是否停止這2個組件
EurekaServerBootstrap
@Bean public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry, EurekaServerContext serverContext) { return new EurekaServerBootstrap(this.applicationInfoManager, this.eurekaClientConfig, this.eurekaServerConfig, registry, serverContext); }
一般叫Bootstrap
的類都是那種掌管項目啟動與停止的,EurekaServerBootstrap
也不例外,它里面就有contextInitialized
項目啟動與contextDestroyed
項目停止/銷毀的方法。
jersey框架 關于jersey框架
的東西,eureka server 對外暴露rest ful接口
,使用的框架就是jersey(這玩意國內很少用),作用/定位就跟我們常用的springmvc 框架差不多。
3. eureka server 初始化源碼解析
3.1 EurekaServerInitializerConfiguration
第2小節(jié)介紹 spring cloud eureka server 啟動的時候自動裝配的一些組件,本小節(jié)就看下eureka server的初始化流程。
在自動裝配類EurekaServerAutoConfiguration
類上面聲明了@Import(EurekaServerInitializerConfiguration.class)
,我們介紹說是導入(加載)EurekaServerInitializerConfiguration
這個配置,一看這個類名字就是eureka server 初始化用的。
@Configuration public class EurekaServerInitializerConfiguration implements ServletContextAware, SmartLifecycle, Ordered { }
@Configuration
是個配置類,實現(xiàn)ServletContextAware,SmartLifecycle,Ordered
接口:
ServletContextAware
作用是自動注入ServletContext
實例。SmartLifecycle
接口 屬于spring 聲明周期的,start 方法執(zhí)行時機是,當spring 的bean都實例化,初始化完事后,會調用SmartLifecycle 的start方法,isAutoStartup 方法返回的true 或者false 決定要不要執(zhí)行start方法,這里isAutoStartup方法返回的true。- stop 方法就是項目停止,容器銷毀的時候會調用。
先來看下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)建了一個線程,先是執(zhí)行eurekaServerBootstrap
的contextInitialized
初始化方法。接著就是發(fā)布 EurekaRegistryAvailableEvent
事件,設置running 為true ,最后就是發(fā)布EurekaServerStartedEvent
事件。 這里我們只關心eurekaServerBootstrap的contextInitialized
方法。
public void contextInitialized(ServletContext context) { initEurekaEnvironment(); initEurekaServerContext(); context.setAttribute(EurekaServerContext.class.getName(), this.serverContext); }
初始化eureka environment, 接著初始化context,最后是將context塞到 ServletContext的屬性中。 initEurekaEnvironment這個我們就不看了。主要看下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)境的時候執(zhí)行if里面的那一堆,這個不看了。
EurekaServerContextHolder.initialize(this.serverContext);
這行代碼沒干啥。
int registryCount = this.registry.syncUp(); this.registry.openForTraffic(this.applicationInfoManager, registryCount);
registry.syncUp()
這個就是去集群中的其他節(jié)點拉取注冊表。下篇文章分析 registry.openForTraffic()
這個是Server端定時清理過期的Client。以后在詳細分析。
3.2 DefaultEurekaServerContext
我們在介紹自動裝配類EurekaServerAutoConfiguration
裝配組件的時候,介紹過EurekaServerContext
,說他字面上是eureka server 上下文,其實就是eureka server 啟動的時候會初始化PeerEurekaNodes 與PeerAwareInstanceRegistry
注冊表,銷毀的是否停止這2個組件 我們來看下 @PostConstruct
注解修飾的initialize
方法
@PostConstruct public void initialize() { this.peerEurekaNodes.start(); this.registry.init(this.peerEurekaNodes); }
干了2件事,啟動peerEurekaNodes
,初始化注冊表。 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é)點信息,就是創(chuàng)建節(jié)點對象。
接著就是創(chuàng)建一個定時任務更新,默認是10分鐘。
注冊表初始化:
@Override public void init(PeerEurekaNodes peerEurekaNodes) throws Exception { this.numberOfReplicationsLastMin.start(); this.peerEurekaNodes = peerEurekaNodes; initializedResponseCache(); scheduleRenewalThresholdUpdateTask(); initRemoteRegionRegistry(); }
numberOfReplicationsLastMin
這是記錄續(xù)約次數的一個組件,用在服務剔除。initializedResponseCache
初始化響應cache ,這個其實就是 服務發(fā)現(xiàn)的時候三級緩存。
參考
springcloud-source-study學習github地址
以上就是Eureka源碼閱讀解析Server服務端啟動流程實例的詳細內容,更多關于Eureka Server服務端啟動流程的資料請關注腳本之家其它相關文章!
相關文章
Java開發(fā)環(huán)境配置及Vscode搭建過程
今天通過圖文并茂的形式給大家介紹Java開發(fā)環(huán)境配置及Vscode搭建過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-07-07springboot中server.ssl.key-store配置路徑的問題小結
這篇文章主要介紹了springboot中server.ssl.key-store配置路徑的問題,文中還記錄了Spring Boot SSL(https)實例,介紹在web程序中使用自簽名的SSL(HTTPS)證書及創(chuàng)建SSL認證,感興趣的朋友跟隨小編一起看看吧2024-02-02Spring?Boot?整合JPA?數據模型關聯(lián)使用操作(一對一、一對多、多對多)
這篇文章主要介紹了Spring?Boot?整合JPA?數據模型關聯(lián)操作(一對一、一對多、多對多),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07springboot2.x實現(xiàn)oauth2授權碼登陸的方法
這篇文章主要介紹了springboot2.x實現(xiàn)oauth2授權碼登陸的方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-08-08