轉自: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; }