在SpringCloud組件:Eureka服務註冊是採用主機名仍是IP地址?文章中咱們講到了服務註冊
的幾種註冊方式
,那麼這幾種註冊方式
的源碼是怎麼實現的呢?咱們帶着這一個疑問來閱讀本章內容可以讓你更深刻了解這塊的知識點!!!git
分析每一種服務註冊方式
源碼執行流程。github
本章以分析源碼爲主,因此不去新建立項目來說解相關內容,咱們使用SpringCloud組件:Eureka服務註冊是採用主機名仍是IP地址?源碼做爲註冊服務
,SpringCloud組件:搭建Eureka服務註冊中心源碼做爲服務註冊中心
,仍是按照以前的運行流程:spring
- 啓動服務註冊中心
- 啓動本章服務項目
- 查看服務列表,服務註冊方式
在開始講解本章註冊方式
以前,咱們須要瞭解總體的配置信息
獲取的流程信息,這樣才能夠分析指定的註冊方式
執行流程。數據庫
EurekaInstanceConfigBean
配置實體在項目啓動時因爲依賴spring-cloud-starter-netflix-eureka-client
內經過配置spring.factories
文件來讓項目啓動時自動加載並實例化org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration
配置類,EurekaClientAutoConfiguration
內會自動實例化EurekaInstanceConfigBean
而且自動綁定eureka.instance
開頭的配置信息(具體爲何會自動映射能夠去了解下@ConfigurationProperties
註解做用),部分源碼以下所示:bash
......
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
配置信息,源碼以下所示:mybatis
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:off
if (!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
進行修改默認值,源碼以下所示:app
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
方法返回的相對應的值。
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
參數才能夠生效。
咱們經過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
三個配置信息時就能夠根據優先級順序達到預期的效果,避免沒有必要的錯誤出現。
本章源碼在這
):訪問碼雲查看源碼若是你有技術相關的問題想要諮詢
恆宇少年
,請去博客首頁左側導航欄,點擊知識星球
微信掃碼加入個人星球。
若是你喜歡
恆宇少年
的相關文章,那麼就去微信公衆號(恆宇少年
)關注我吧!!! 固然你也能夠去 SpringCloud碼雲源碼 項目底部掃描微信公衆號二維碼關注我,感謝閱讀!!!
這段時間一直在編寫開源的相關框架,致力於公司使用的框架升級以及開源計劃,將公司使用到的工具
以及插件
進行升級重構而且開源。
code-builder
代碼生成器根據你提供的模板文件(目前支持freemarker
)自動生成實體類,能夠很大頗有效的提升開發效率。 Gitee地址
:gitee.com/hengboy/cod… Github地址
:github.com/hengyuboy/c…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…