Nacos 2.2.x版本客户端注册监听器时的多网卡问题
背景
在本地环境启动Nacos和SpringBoot应用测试Nacos的配置监听特性,Nacos控制台在本地以单机模式启动,SpringBoot应用在IDEA中启动;本地环境有一个VMware虚拟机实例。
问题
Nacos控制台绑定的IP为VMware虚拟机网卡的IP
Nacos控制台启动后绑定的IP为VMware虚拟网卡的IP:192.168.232.1

实际期望绑定到如下局域网唯一IP:

SpringBoot应用中的Nacos SDK注册到Nacos中的监听IP为VMware虚拟机网卡的IP
SpringBoot应用中引用Nacos-Client,然后使用ConfigService注册配置监听器,实际发现上报的客户端IP如下(虽然VMware虚拟网卡的ip也能正常监听配置变更):

同样期望绑定到192.168.166开头的局域网唯一IP。
解决方案
修改Nacos控制台配置以指定控制台IP
2.3.x版本及之前(实际测试有效):
nacos.inetutils.ip-address=你的ip
2.4.x版本及之后(官方文档给出的方案):
nacos.server.ip=你的ip
修改Nacos SDK注册监听器时上报到控制台的Client IP
Nacos SDK获取本地IP的逻辑如下:
package com.alibaba.nacos.api.utils;
public class NetUtils {
private static final String CLIENT_LOCAL_IP_PROPERTY = "com.alibaba.nacos.client.local.ip";
private static final String CLIENT_LOCAL_PREFER_HOSTNAME_PROPERTY = "com.alibaba.nacos.client.local.preferHostname";
private static final String LEGAL_LOCAL_IP_PROPERTY = "java.net.preferIPv6Addresses";
private static final String DEFAULT_SOLVE_FAILED_RETURN = "resolve_failed";
private static String localIp;
/**
* Get local ip.
*
* @return local ip
*/
public static String localIP() {
if (!StringUtils.isEmpty(localIp)) {
return localIp;
}
if (System.getProperties().containsKey(CLIENT_LOCAL_IP_PROPERTY)) {
return localIp = System.getProperty(CLIENT_LOCAL_IP_PROPERTY, getAddress());
}
localIp = getAddress();
return localIp;
}
private static String getAddress() {
InetAddress inetAddress = findFirstNonLoopbackAddress();
if (inetAddress == null) {
return DEFAULT_SOLVE_FAILED_RETURN;
}
boolean preferHost = Boolean.parseBoolean(System.getProperty(CLIENT_LOCAL_PREFER_HOSTNAME_PROPERTY));
return preferHost ? inetAddress.getHostName() : inetAddress.getHostAddress();
}
private static 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()) {
if (ifc.getIndex() < lowest || result == null) {
lowest = ifc.getIndex();
} else {
continue;
}
for (Enumeration<InetAddress> addrs = ifc.getInetAddresses(); addrs.hasMoreElements(); ) {
InetAddress address = addrs.nextElement();
boolean isLegalIpVersion = Boolean.parseBoolean(System.getProperty(LEGAL_LOCAL_IP_PROPERTY))
? address instanceof Inet6Address : address instanceof Inet4Address;
if (isLegalIpVersion && !address.isLoopbackAddress()) {
result = address;
}
}
}
}
} catch (IOException ex) {
//ignore
}
if (result != null) {
return result;
}
try {
return InetAddress.getLocalHost();
} catch (UnknownHostException e) {
//ignore
}
return null;
}
}
默认返回本机第一个非回环地址的ip,如果指定了com.alibaba.nacos.client.local.ip则使用指定的ip作为本地ip,所以只需要在启动命令加上如下部分即可
java -Dcom.alibaba.nacos.client.local.ip=你的IP app.jar
在IDEA中配置方法如下:

附录
Nacos SDK中监听器的使用注意事项
Nacos SDK中的监听器接口为com.alibaba.nacos.api.config.listener.Listener,其包含一个名为com.alibaba.nacos.client.config.listener.impl.AbstractConfigChangeListener的默认实现,但是这个实现默认仅支持对properties和yaml两种类型的配置进行变更前后分析,其他类型的配置需要自己实现com.alibaba.nacos.api.config.listener.ConfigChangeParser接口并通过Nacos的SPI注册进去,部分源码如下:
package com.alibaba.nacos.client.config.impl;
public class ConfigChangeHandler {
// ......
private ConfigChangeHandler() {
this.parserList = new LinkedList<>();
Collection<ConfigChangeParser> loader = NacosServiceLoader.load(ConfigChangeParser.class);
this.parserList.addAll(loader);
this.parserList.add(new PropertiesChangeParser());
this.parserList.add(new YmlChangeParser());
}
// ......
}
我这里要实现的监听js脚本文件变化并更新,只需要实现com.alibaba.nacos.api.config.listener.AbstractListener就行了。

浙公网安备 33010602011771号