SpringCloud Eureka 服務(wù)注冊實(shí)現(xiàn)過程
一、將服務(wù)注冊到Eureka
一個(gè)SpringBoot應(yīng)用如果要注冊到Spring Cloud環(huán)境(Greenwich.SR3版本),步驟很簡單:
pom.xml中添加啟動(dòng)器:spring-cloud-starter-netflix-eureka-client;
增加配置:eureka.client.serviceUrl.defaultZone: http://localhost:8100/eureka/;
啟動(dòng)應(yīng)用;
如果注冊中心正常,此時(shí)就能在注冊中心發(fā)現(xiàn)這個(gè)應(yīng)用了,如下圖紅框所示:
按照spring.factories中的配置,EurekaClientAutoConfiguration中的配置都會(huì)生效,包括下面這段代碼返回的bean:
@Bean public DiscoveryClient discoveryClient(EurekaInstanceConfig config, EurekaClient client) { return new EurekaDiscoveryClient(config, client); }
spring容器初始化時(shí)會(huì)實(shí)例化所有單例bean,就會(huì)執(zhí)行EurekaClientAutoConfiguration的discoveryClient方法獲取這個(gè)bean實(shí)例,于是就構(gòu)造了一個(gè)EurekaDiscoveryClient對象;
注意EurekaDiscoveryClient的構(gòu)造方法,第二個(gè)入?yún)⑹莄om.netflix.discovery.EurekaClient類型,此對象同樣來自EurekaClientAutoConfiguration類,如下方法:
@Bean(destroyMethod = "shutdown") @ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT) @org.springframework.cloud.context.config.annotation.RefreshScope @Lazy public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config, EurekaInstanceConfig instance) { manager.getInfo(); // force initialization return new CloudEurekaClient(manager, config, this.optionalArgs,this.context); }
CloudEurekaClient的父類com.netflix.discovery.DiscoveryClient來自netflix發(fā)布的eureka-client包中,所以可以這么理解:EurekaDiscoveryClient類是個(gè)代理身份,真正的服務(wù)注冊發(fā)現(xiàn)是委托給netflix的開源包來完成的,我們可以專心的使用SpringCloud提供的服務(wù)注冊發(fā)現(xiàn)功能,只需要知道EurekaDiscoveryClient即可,真正的服務(wù)是eureka-client來完成的;
接下來需要關(guān)注com.netflix.discovery.DiscoveryClient的構(gòu)造方法,因?yàn)檫@里面有服務(wù)注冊的邏輯,整個(gè)構(gòu)造方法內(nèi)容太多,無需都細(xì)看,只看關(guān)鍵代碼即可;
DiscoveryClient的構(gòu)造方法中,最熟悉的應(yīng)該是下圖紅框中這段日志輸出的了:
對應(yīng)的應(yīng)用啟動(dòng)日志中就有這段日志輸出,如下圖紅框:
紅框中的”us-east-1”,是默認(rèn)的region,來自配置類EurekaClientConfigBean,這里面有各種eureka相關(guān)的配置信息,以及默認(rèn)配置,如下圖:
繼續(xù)看DiscoveryClient的構(gòu)造方法,服務(wù)注冊相關(guān)的initScheduledTasks方法在此被調(diào)用,如下圖:
initScheduledTasks方法的內(nèi)容如下,請注意中文注釋:
private void initScheduledTasks() { //獲取服務(wù)注冊列表信息 if (clientConfig.shouldFetchRegistry()) { //服務(wù)注冊列表更新的周期時(shí)間 int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds(); int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound(); //定時(shí)更新服務(wù)注冊列表 scheduler.schedule( new TimedSupervisorTask( "cacheRefresh", scheduler, cacheRefreshExecutor, registryFetchIntervalSeconds, TimeUnit.SECONDS, expBackOffBound, new CacheRefreshThread() //該線程執(zhí)行更新的具體邏輯 ), registryFetchIntervalSeconds, TimeUnit.SECONDS); } if (clientConfig.shouldRegisterWithEureka()) { //服務(wù)續(xù)約的周期時(shí)間 int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs(); int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound(); //應(yīng)用啟動(dòng)可見此日志,內(nèi)容是:Starting heartbeat executor: renew interval is: 30 logger.info("Starting heartbeat executor: " + "renew interval is: " + renewalIntervalInSecs); // 定時(shí)續(xù)約 scheduler.schedule( new TimedSupervisorTask( "heartbeat", scheduler, heartbeatExecutor, renewalIntervalInSecs, TimeUnit.SECONDS, expBackOffBound, new HeartbeatThread() //該線程執(zhí)行續(xù)約的具體邏輯 ), renewalIntervalInSecs, TimeUnit.SECONDS); //這個(gè)Runable中含有服務(wù)注冊的邏輯 instanceInfoReplicator = new InstanceInfoReplicator( this, instanceInfo, clientConfig.getInstanceInfoReplicationIntervalSeconds(), 2); // burstSize statusChangeListener = new ApplicationInfoManager.StatusChangeListener() { @Override public String getId() { return "statusChangeListener"; } @Override public void notify(StatusChangeEvent statusChangeEvent) { if (InstanceStatus.DOWN == statusChangeEvent.getStatus() || InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) { // log at warn level if DOWN was involved logger.warn("Saw local status change event {}", statusChangeEvent); } else { logger.info("Saw local status change event {}", statusChangeEvent); } instanceInfoReplicator.onDemandUpdate(); } }; if (clientConfig.shouldOnDemandUpdateStatusChange()) { applicationInfoManager.registerStatusChangeListener(statusChangeListener); } //服務(wù)注冊 instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds()); } else { logger.info("Not registering with Eureka server per configuration"); } }
上述代碼中有幾處需要注意,這些關(guān)鍵點(diǎn)在后面的章節(jié)將繼續(xù)展開:
a. 周期性更新服務(wù)列表;
b. 周期性服務(wù)續(xù)約;
c. 服務(wù)注冊邏輯被放入Runnable實(shí)現(xiàn)類InstanceInfoReplicator之中,在新線程中執(zhí)行;
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java連接redis報(bào)錯(cuò)timed?out問題的解決辦法
最近項(xiàng)目開發(fā)中用到了Redis,下面這篇文章主要給大家介紹了關(guān)于Java連接redis報(bào)錯(cuò)timed?out問題的解決辦法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-02-02SpringBoot通過源碼探究靜態(tài)資源的映射規(guī)則實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot通過源碼探究靜態(tài)資源的映射規(guī)則實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05淺談Java中的重載,重寫,多態(tài),靜態(tài)綁定、動(dòng)態(tài)綁定
這篇文章主要介紹了淺談Java中的重載,重寫,多態(tài),靜態(tài)綁定、動(dòng)態(tài)綁定,具有一定借鑒價(jià)值2018-01-01解決cmd運(yùn)行java程序“找不到文件”提示的方案
在本篇文章里小編給大家分享的是關(guān)于解決cmd運(yùn)行java程序“找不到文件”提示的方案,有需要的朋友們可以參考下。2020-02-02基于Springboot執(zhí)行多個(gè)定時(shí)任務(wù)并動(dòng)態(tài)獲取定時(shí)任務(wù)信息
這篇文章主要為大家詳細(xì)介紹了基于Springboot執(zhí)行多個(gè)定時(shí)任務(wù)并動(dòng)態(tài)獲取定時(shí)任務(wù)信息,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04簡單講解Java的Socket網(wǎng)絡(luò)編程的多播與廣播實(shí)現(xiàn)
這篇文章主要介紹了Java的Socket網(wǎng)絡(luò)編程的多播與廣播實(shí)現(xiàn),包括網(wǎng)絡(luò)編程發(fā)送和接受數(shù)據(jù)的一些基礎(chǔ)知識(shí)整理,需要的朋友可以參考下2016-01-01Java實(shí)現(xiàn)的圖片上傳工具類完整實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)的圖片上傳工具類,涉及java針對圖片文件的檢查、上傳、清除等相關(guān)操作技巧,需要的朋友可以參考下2017-10-10微信公眾平臺(tái)開發(fā)實(shí)戰(zhàn)Java版之微信獲取用戶基本信息
這篇文章主要介紹了微信公眾平臺(tái)開發(fā)實(shí)戰(zhàn)Java版之微信獲取用戶基本信息 的相關(guān)資料,需要的朋友可以參考下2015-12-12