重写Nacos服务发现逻辑动态修改远程服务IP地址
背景
还是先说下做这个的背景,开发环境上了K8S,所有的微服务都注册在K8S内的Nacos,注册地址为K8S内部虚拟IP,K8S内的服务之间相互调用没有问题,但是本机开发联调调用其他微服务就访问不到。
解决方案
1、KT Connect,可以理解为一个VPN工具,可以和K8S网络联通,缺点是配置繁琐,每次开发都需要启动KT Connect程序;
2、配置Ribbon的listOfServers,配置如下:
<nacosServiceName>.ribbon.listOfServers=<ip:port>
3、Nacos Client从Nacos Server获取服务列表时,修改远程服务对应的IP地址。
重写NacosNamingService
1、看了下nacos-client源码,发现有个NacosNamingService类,主要是服务发现的实现类,可以从这里入手修改远程服务注册IP;
2、NacosNamingService是在NacosDiscoveryClientAutoConfiguration通过注入NacosDiscoveryProperties初始化的,具体源码如下:
@Bean @ConditionalOnMissingBean public NacosDiscoveryProperties nacosProperties() { return new NacosDiscoveryProperties(); }
3、跟踪到NacosDiscoveryProperties,初始化NacosNamingService的核心代码如下:
public NamingService namingServiceInstance() { if (null != this.namingService) { return this.namingService; } else { Properties properties = new Properties(); properties.put("serverAddr", this.serverAddr); properties.put("namespace", this.namespace); properties.put("com.alibaba.nacos.naming.log.filename", this.logName); if (this.endpoint.contains(":")) { int index = this.endpoint.indexOf(":"); properties.put("endpoint", this.endpoint.substring(0, index)); properties.put("endpointPort", this.endpoint.substring(index + 1)); } else { properties.put("endpoint", this.endpoint); } properties.put("accessKey", this.accessKey); properties.put("secretKey", this.secretKey); properties.put("clusterName", this.clusterName); properties.put("namingLoadCacheAtStart", this.namingLoadCacheAtStart); try { this.namingService = NacosFactory.createNamingService(properties); } catch (Exception var3) { log.error("create naming service error!properties={},e=,", this, var3); return null; } return this.namingService; } }
4、我们直接重新namingServiceInstance方法就可以了,具体实现代码如下:
@Slf4j @Configuration @ConditionalOnNacosDiscoveryEnabled @ConditionalOnProperty( name = {"spring.profiles.active"}, havingValue = "dev" ) @AutoConfigureBefore({NacosDiscoveryClientAutoConfiguration.class}) public class DevEnvironmentNacosDiscoveryClient { @Bean @ConditionalOnMissingBean public NacosDiscoveryProperties nacosProperties() { return new DevEnvironmentNacosDiscoveryProperties(); } static class DevEnvironmentNacosDiscoveryProperties extends NacosDiscoveryProperties { private NamingService namingService; @Override public NamingService namingServiceInstance() { if (null != this.namingService) { return this.namingService; } else { Properties properties = new Properties(); properties.put("serverAddr", super.getServerAddr()); properties.put("namespace", super.getNamespace()); properties.put("com.alibaba.nacos.naming.log.filename", super.getLogName()); if (super.getEndpoint().contains(":")) { int index = super.getEndpoint().indexOf(":"); properties.put("endpoint", super.getEndpoint().substring(0, index)); properties.put("endpointPort", super.getEndpoint().substring(index + 1)); } else { properties.put("endpoint", super.getEndpoint()); } properties.put("accessKey", super.getAccessKey()); properties.put("secretKey", super.getSecretKey()); properties.put("clusterName", super.getClusterName()); properties.put("namingLoadCacheAtStart", super.getNamingLoadCacheAtStart()); try { this.namingService = new DevEnvironmentNacosNamingService(properties); } catch (Exception var3) { log.error("create naming service error!properties={},e=,", this, var3); return null; } return this.namingService; } } } static class DevEnvironmentNacosNamingService extends NacosNamingService { public DevEnvironmentNacosNamingService(Properties properties) { super(properties); } @Override public List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy) throws NacosException { List<Instance> instances = super.selectInstances(serviceName, clusters, healthy); instances.stream().forEach(instance -> instance.setIp("10.101.232.24")); return instances; } } }