本节解释为什么配置eureka.instance.prefer-ip-address = true时,注册到Eureka Server上的是IP,以及是什么IP

  • Post author:
  • Post category:其他


老套路,定位问题从配置开始。

(1) 我们通过

eureka.instance.prefer-ip-address

配置项,可以找到源码


1

org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.preferIpAddress

(2) preferIpAddress被哪里调用,可以找到


1

org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.getHostName(boolean)

代码如下:


1
2
3
4
5
6
7
8


@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在


1

org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean

的构造方法中实例化!我们来阅读该类的构造方法:


1
2
3
4
5
6



public


EurekaInstanceConfigBean


(InetUtils inetUtils)


{

this

.inetUtils = inetUtils;

this

.hostInfo =

this

.inetUtils.findFirstNonLoopbackHostInfo();

this

.ipAddress =

this

.hostInfo.getIpAddress();

this

.hostname =

this

.hostInfo.getHostname();
}

从中 可以看到,hostInfo是调用了


1

this.inetUtils.findFirstNonLoopbackHostInfo();

从中可以看到,原来hostInfo是调用了


1

org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackHostInfo()

(4) 阅读


1

org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackHostInfo()

可以看到以下代码:


1
2
3
4
5
6
7
8
9
10

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;
}

我们再看一下该类的


1

org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackAddress()

方法:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51



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的。

原因是:在


1

org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.setIpAddress(String)

中:


1
2
3
4



public


void


setIpAddress


(String ipAddress)


{

this

.ipAddress = ipAddress;

this

.hostInfo.override =

true

;
}

这边设置了this.hostInfo.override,因此会导致getHostName方法不会进if语句,直接返回this.ipAddress。


1
2
3
4
5
6
7
8


@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;
}



B.T.W

回到上文的


1

org.springframework.cloud.commons.util.InetUtils.findFirstNonLoopbackAddress()

方法,上面有很多ignoreXXX的代码。那么,如何配置想要忽略的网卡或者IP地址呢?

答案非常简单,详见Spring Cloud官方文档:


http://cloud.spring.io/spring-cloud-static/Camden.SR3/#ignore-network-interfaces

当然了,这些配置的本意并不是用来注册到Eureka上的,而是用作其他用途,只不过如果没有设置eureka.instance.ip-address时,这个IP就是注册到Eureka Server上的IP。

我们可以在应用的/env端点看到Spring为我们挑选的IP:


1
2
3
4

springCloudClientHostInfo: {
spring.cloud.client.hostname: “itmuch”,
spring.cloud.client.ipAddress: “192.168.0.59”
},