Eureka服务注册过程详解之IpAddress

Posted yunyunde

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Eureka服务注册过程详解之IpAddress相关的知识,希望对你有一定的参考价值。

转自: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;

 

以上是关于Eureka服务注册过程详解之IpAddress的主要内容,如果未能解决你的问题,请参考以下文章

Eureka 源码之客户端首次获取注册表

Eureka服务发现注册详解

玩转springcloud系列:注册中心-Eureka

深入理解SpringCloud之Eureka注册过程分析

SpringCloud - Spring Cloud Netflix 之 Eureka 控制台界面详解

Spring Cloud系列之 EurekaZookeeperConsul