轉自:http://www.itmuch.com/spring-cloud-code-read/spring-cloud-code-read-eureka-registry-ip/
系列文章都寫得特別好,轉過來給自己參考。
先說一下結論,
如果eureka.instance.prefer-ip-address = true 則Spring就會為我們自動獲取IP;
如果eureka.instance.ip-address 與 eureka.instance.prefer-ip-address = true 同時設置,則使用eureka.instance.ip-address 設置的ip;
這些配置的本意並不是用來注冊到Eureka上的,而是用作其他用途,只不過如果沒有設置eureka.instance.ip-address時,這個IP就是注冊到Eureka Server上的IP。
我們可以在應用的/env端點看到Spring為我們挑選的IP:
springCloudClientHostInfo: {
spring.cloud.client.hostname: "itmuch",
spring.cloud.client.ipAddress: "192.168.0.59"
},
本文內容:
- 微服務注冊到Eureka Server上的粗粒度過程
eureka.instance.prefer-ip-address = true時,發生的一些事- 深度理解
eureka.instance.ip-address和eureka.instance.prefer-ip-address = true。
為什么配置eureka.instance.prefer-ip-address = true時,注冊到Eureka Server上的是IP,以及是什么IP
(1) 我們通過eureka.instance.prefer-ip-address 配置項,可以找到源碼
org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.preferIpAddress
(2) preferIpAddress被哪里調用,可以找到
org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.getHostName(boolean)
代碼如下:
@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;
}
從這里我們可以知道,為什么配置eureka.instance.prefer-ip-address = true 就可以將IP注冊到Eureka Server上,而如果不配置就是機器的主機名。
我們看到以上代碼有個hostInfo,這是在哪里實例化的呢?
(3) hostInfo在
org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean
的構造方法中實例化!我們來閱讀該類的構造方法:
public EurekaInstanceConfigBean(InetUtils inetUtils) {
this.inetUtils = inetUtils;
this.hostInfo = this.inetUtils.findFirstNonLoopbackHostInfo();
this.ipAddress = this.hostInfo.getIpAddress();
this.hostname = this.hostInfo.getHostname();
}
從中 可以看到,hostInfo是調用了
this.inetUtils.findFirstNonLoopbackHostInfo();
從中可以看到,原來hostInfo是調用了
org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackHostInfo()
(4) 閱讀
org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackHostInfo()
可以看到以下代碼:
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;
}
我們再看一下該類的
org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackAddress()
方法:
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()
&& !ignoreAddress(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;
}
至此,終於找到了獲得IP的詳細方法,原來只需要配置eureka.instance.prefer-ip-address = true,Spring就會自動為我們獲取第一個非回環IP地址(這只是簡單的說法,事實上這段代碼有些容錯的處理)。
eureka.instance.ip-address和eureka.instance.prefer-ip-address = true同時設置,會用自動獲取的ip還是手動設置的?
上文是討論設置eureka.instance.prefer-ip-address = true ,但沒有指定eureka.instance.ip-address 的情況。那么如果兩者都被指定了,Spring會怎么處理呢?是使用eureka.instance.ip-address手動設置的IP,還是用上面自動獲取的IP呢?
答案是聽eureka.instance.ip-address的。
原因是:在
org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.setIpAddress(String)
中:
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
this.hostInfo.override = true;
}
這邊設置了this.hostInfo.override,因此會導致getHostName方法不會進if語句,直接返回this.ipAddress。
@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;
}
