Eureka服务注册过程详解之IpAddress(详解eureka.instance.prefer-ip-address = true 与 eureka.instance.prefer-ip-address)

简介: 阅读本文你将了解微服务注册到Eureka Server上的粗粒度过程eureka.instance.prefer-ip-address = true 时,发生的一些事深度理解eureka.instance.ip-address 和eureka.instance.prefer-ip-address = true 。

阅读本文你将了解

  • 微服务注册到Eureka Server上的粗粒度过程
  • eureka.instance.prefer-ip-address = true 时,发生的一些事
  • 深度理解eureka.instance.ip-addresseureka.instance.prefer-ip-address = true
  • 杂谈

注:本篇较长、枯燥、烧脑,并且涉及的范围相对广,建议选择一个舒服的姿势阅读。

分析,eureka.instance.prefer-ip-address

  • 本节解释为什么配置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;
}

B.T.W

回到上文的

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:

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

本文链接: http://www.itmuch.com/spring-cloud-code-read/spring-cloud-code-read-eureka-registry-ip/
**版权声明: **本博客由周立创作,采用 CC BY 3.0 CN 许可协议。可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。

目录
相关文章
|
Java API Maven
敏感数据的保护伞——SpringBoot Jasypt加密库的使用
我们经常会在yml配置文件中存放一些敏感数据,比如数据库的用户名、密码,第三方应用的秘钥等等。这些信息直接以明文形式展示在文件中,无疑是存在较大的安全隐患的,所以今天这篇文章,我会借助jasypt实现yml文件中敏感信息的加密处理。
5152 1
敏感数据的保护伞——SpringBoot Jasypt加密库的使用
|
存储 SQL Oracle
Oracle使用expdp/impdp实现全库导入导出的整体流程
Oracle的全库导入,首先一点必须先创建数据库,创建了数据库,才能往该数据库导入所有数据。相对来说,使用Oracle进行数据导入导出还很有些“麻烦”的,大多数资料上来就是......
13532 0
Oracle使用expdp/impdp实现全库导入导出的整体流程
|
Prometheus 监控 安全
SpringBoot Actuator未授权访问漏洞的解决方法
SpringBoot Actuator未授权访问漏洞的解决方法Actuator 是 SpringBoot 提供的用来对应用系统进行自省和监控的功能模块,借助于 Actuator 开发者可以很方便地对应用系统某些监控指标进行查看、统计等。
31051 0
|
异构计算
【自己动手画CPU】运算器设计
【自己动手画CPU】运算器设计
695 0
|
Java Spring
聊一下Spring Boot配置的加载顺序
聊一下Spring Boot配置的加载顺序
250 0
|
4月前
|
SQL 关系型数据库 MySQL
SQL 判断是否“存在”?99% 的人还在写错!
在判断数据是否存在时,使用 `COUNT(*)` 会导致性能浪费,因为它会统计所有匹配记录,而我们只需知道是否存在即可。推荐使用 `EXISTS`,它在找到第一条匹配记录后立即返回,大幅提升查询效率。本文通过多个示例展示了 `EXISTS` 的用法,并对比了其与 `COUNT(*)` 的性能差异,帮助你写出更高效、优雅的 SQL 查询。
433 3
|
缓存 Linux 开发工具
CentOS 7- 配置阿里镜像源
阿里镜像官方地址http://mirrors.aliyun.com/ 1、点击官方提供的相应系统的帮助 :2、查看不同版本的系统操作: 下载源1、安装wget yum install -y wget2、下载CentOS 7的repo文件wget -O /etc/yum.
263294 0
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
|
Linux 网络架构 Windows
TTL传输中过期原因,ttl传输中过期的解决办法(ttl传输中过期怎么解决)
A3: 实际上,TTL值需依据实际网络环境设定。过小的TTL值可能导致数据包过早丢弃,影响通信;反之,过大的TTL值则可能占用不必要的网络资源。因此,科学合理的TTL值设定是平衡通信效率与资源利用的关键。
3278 0
|
Java Apache Maven
【异常解决】Handler dispatch failed;nested exception is java.lang.NoClassDefFoundError: org/apache/common
【异常解决】Handler dispatch failed;nested exception is java.lang.NoClassDefFoundError: org/apache/common
10120 0