javascript
SpringCloud组件 源码剖析:Eureka服务注册方式流程全面分析
在SpringCloud組件:Eureka服務注冊是采用主機名還是IP地址?文章中我們講到了服務注冊的幾種注冊方式,那么這幾種注冊方式的源碼是怎么實現的呢?我們帶著這一個疑問來閱讀本章內容能夠讓你更深入了解這塊的知識點!!!
本章目標
分析每一種服務注冊方式源碼執行流程。
構建項目
本章以分析源碼為主,所以不去新創建項目來講解相關內容,我們使用SpringCloud組件:Eureka服務注冊是采用主機名還是IP地址?源碼作為注冊服務,SpringCloud組件:搭建Eureka服務注冊中心源碼作為服務注冊中心,還是按照之前的運行流程:
配置信息獲取執行流程
在開始講解本章注冊方式之前,我們需要了解整體的配置信息獲取的流程信息,這樣才可以分析指定的注冊方式執行流程。
第一步:實例化EurekaInstanceConfigBean配置實體
在項目啟動時由于依賴spring-cloud-starter-netflix-eureka-client內通過配置spring.factories文件來讓項目啟動時自動加載并實例化org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration配置類,EurekaClientAutoConfiguration內會自動實例化EurekaInstanceConfigBean并且自動綁定eureka.instance開頭的配置信息(具體為什么會自動映射可以去了解下@ConfigurationProperties注解作用),部分源碼如下所示:
...... public class EurekaClientAutoConfiguration {//省略部分源碼@Bean@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils, ManagementMetadataProvider managementMetadataProvider) {//省略部分源碼// 傳遞EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);// 省略部分源碼}//省略部分源碼 } 復制代碼EurekaClientAutoConfiguration#eurekaInstanceConfigBean方法只有滿足@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)表達式后才會去實例化,并且把實例化對象放入到IOC容器內容,BeanId為eurekaInstanceConfigBean,也就是方法的名稱。 在EurekaClientAutoConfiguration#eurekaInstanceConfigBean方法中有這么一行代碼我們可以進行下一步的分析
// 通過有參構造函數實例化EurekaInstanceConfigBean配置實體 EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils); 復制代碼通過調用EurekaInstanceConfigBean(InetUtils inetUtils)構造函數來進行實例化EurekaInstanceConfigBean對象,在這個構造函數內也有一些實例化的工作,源碼如下:
public EurekaInstanceConfigBean(InetUtils inetUtils) {this.inetUtils = inetUtils;this.hostInfo = this.inetUtils.findFirstNonLoopbackHostInfo();this.ipAddress = this.hostInfo.getIpAddress();this.hostname = this.hostInfo.getHostname(); } 復制代碼第二步:InetUtils#findFirstNonLoopbackHostInfo獲取主機基本信息
在構造函數EurekaInstanceConfigBean(InetUtils inetUtils)源碼實現內hostInfo主機信息通過了InetUtils#findFirstNonLoopbackHostInfo方法來進行實例化,我們來看看這個方法的具體實現邏輯,它會自動讀取系統網卡列表然再進行循環遍歷查詢正在UP狀態的網卡信息,如果沒有查詢到網卡信息,則使用默認的HostName、IpAddress配置信息,源碼如下所示:
public HostInfo findFirstNonLoopbackHostInfo() {InetAddress address = findFirstNonLoopbackAddress();if (address != null) {return convertAddress(address);}HostInfo hostInfo = new HostInfo();hostInfo.setHostname(this.properties.getDefaultHostname());hostInfo.setIpAddress(this.properties.getDefaultIpAddress());return hostInfo; }public InetAddress findFirstNonLoopbackAddress() {InetAddress result = null;try {int lowest = Integer.MAX_VALUE;for (Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces(); nics.hasMoreElements();) {NetworkInterface ifc = nics.nextElement();if (ifc.isUp()) {log.trace("Testing interface: " + ifc.getDisplayName());if (ifc.getIndex() < lowest || result == null) {lowest = ifc.getIndex();}else if (result != null) {continue;}// @formatter:offif (!ignoreInterface(ifc.getDisplayName())) {for (Enumeration<InetAddress> addrs = ifc.getInetAddresses(); addrs.hasMoreElements();) {InetAddress address = addrs.nextElement();if (address instanceof Inet4Address&& !address.isLoopbackAddress()&& isPreferredAddress(address)) {log.trace("Found non-loopback interface: "+ ifc.getDisplayName());result = address;}}}// @formatter:on}}}catch (IOException ex) {log.error("Cannot get first non-loopback address", ex);}if (result != null) {return result;}try {return InetAddress.getLocalHost();}catch (UnknownHostException e) {log.warn("Unable to retrieve localhost");}return null; } 復制代碼默認的HostName、IpAddress屬性配置信息在InetUtilsProperties配置實體類內,如果不進行設置則直接使用默認值,如果你想更換默認值,那么你可以在application.yml配置文件內通過設置spring.cloud.inetutils.defaultHostname、spring.cloud.inetutils.defaultIpAddress進行修改默認值,源碼如下所示:
public class InetUtilsProperties {public static final String PREFIX = "spring.cloud.inetutils";/*** The default hostname. Used in case of errors.*/private String defaultHostname = "localhost";/*** The default ipaddress. Used in case of errors.*/private String defaultIpAddress = "127.0.0.1"; } 復制代碼第三步:EurekaInstanceConfigBean#getHostName方法實現
getHostName是一個Override的方法,繼承于com.netflix.appinfo.EurekaInstanceConfig接口,該方法有個boolean類型的參數refresh來判斷是否需要刷新重新獲取主機網絡基本信息,當傳遞refresh=false并且在application.yml配置文件內并沒有進行手動設置eureka.instance.hostname以及eureka.instance.ip-address參數則會根據eureka.instance.prefer-ip-address設置的值進行返回信息,源碼如下所示:
@Override public String getHostName(boolean refresh) {if (refresh && !this.hostInfo.override) {this.ipAddress = this.hostInfo.getIpAddress();this.hostname = this.hostInfo.getHostname();}return this.preferIpAddress ? this.ipAddress : this.hostname; } 復制代碼默認注冊方式源碼分析
由于在實例化EurekaInstanceConfigBean配置實體類時,構造函數進行了獲取第一個非回環主機信息,默認的hostName以及ipAddress參數則是會直接使用InetUtils#findFirstNonLoopbackHostInfo方法返回的相對應的值。
IP優先注冊方式源碼分析
EurekaInstanceConfigBean#getHostName方法直接調用本類重載方法getHostName(boolean refresh)并且傳遞參數為false,根據第三步源碼我們就可以看到:
return this.preferIpAddress ? this.ipAddress : this.hostname; 復制代碼如果eureka.instance.prefer-ip-address參數設置了true就會返回eureka.instance.ip-address的值,這樣我們就可以從中明白為什么主動設置eureka.instance.ip-address參數后需要同時設置eureka.instance.prefer-ip-address參數才可以生效。
指定IP、HostName源碼分析
我們通過application.yml配置文件進行設置eureka.instance.hostname以及eureka.instance.ip-address后會直接替換原默認值,在EurekaInstanceConfigBean#getHostName中也是返回的this.hostname、this.ipAddress所以在這里設置后會直接生效作為返回的配置值。
總結
我們通過源碼進行分析服務注冊方式執行流程,這樣在以后進行配置eureka.instance.hostname、eureka.instance.prefer.ip-address、eureka.instance.ip-address三個配置信息時就可以根據優先級順序達到預期的效果,避免沒有必要的錯誤出現。
源碼位置
- SpringBoot配套源碼地址:訪問碼云查看源碼、訪問GitHub查看源碼
- SpringCloud配套源碼地址(本章源碼在這):訪問碼云查看源碼
有問題要問?
如果你有技術相關的問題想要咨詢恒宇少年,請去博客首頁左側導航欄,點擊知識星球微信掃碼加入我的星球。
與恒宇少年面對面
如果你喜歡恒宇少年的相關文章,那么就去微信公眾號(恒宇少年)關注我吧!!! 當然你也可以去 SpringCloud碼云源碼 項目底部掃描微信公眾號二維碼關注我,感謝閱讀!!!
學習目錄推薦
- SpringCloud相關系列文章訪問:www.jianshu.com/p/64e4aaada…
- SpringBoot相關系列文章請訪問:www.jianshu.com/p/9a08417e4…
- QueryDSL相關系列文章請訪問:www.jianshu.com/p/99a5ec5c3…
- SpringDataJPA相關系列文章請訪問:www.jianshu.com/p/615ed9c1f…
開源信息
這段時間一直在編寫開源的相關框架,致力于公司使用的框架升級以及開源計劃,將公司使用到的工具以及插件進行升級重構并且開源。
- 代碼生成器(Code-Builder) code-builder代碼生成器根據你提供的模板文件(目前支持freemarker)自動生成實體類,可以很大很有效的提高開發效率。 Gitee地址:gitee.com/hengboy/cod… Github地址:github.com/hengyuboy/c…
- 持久化框架(MyBatis-Enhance) mybatis-enhance是一個對mybatis框架的增強封裝,提供一系列的內部方法來完成單表數據的操作,多表數據提供DSL方式進行操作。 Gitee地址:gitee.com/hengboy/myb… Github地址:github.com/hengyuboy/m…
- 自動分頁插件 MyBatis-Pageable是一款自動化分頁的插件,基于MyBatis內部的插件Interceptor攔截器編寫完成,攔截Executor.query的兩個重載方法計算出分頁的信息以及根據配置的數據庫Dialect自動執行不同的查詢語句完成總數量的統計。 Gitee地址:gitee.com/hengboy/myb…
總結
以上是生活随笔為你收集整理的SpringCloud组件 源码剖析:Eureka服务注册方式流程全面分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java中的JDBC是什么?
- 下一篇: 浅谈移动端中的视口(viewport)