栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Gateway集成 Nacos注册中心不能够发现服务的问题解决

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Gateway集成 Nacos注册中心不能够发现服务的问题解决

一、问题描述

我们现在是在用Nacos替换Eureka,原来Eureka和Spring gateway运行正常,可以通过Spring gateway调用注册到Eureka中的服务。

当前Spring cloud的版本是Hoxton.SR8,Nacos discovery的版本为0.9.0.RELEASE,使用的Nacos版本为2.0.3。

Nacos替换Eureka改动的地方如下:

1、去掉POM中Eureka的引入;

2、去掉主类中引入的@EnableEurekaClient注解;

3、引入Nacos依赖:


  org.springframework.cloud
  spring-cloud-starter-alibaba-nacos-discovery
  0.9.0.RELEASE
  
    
        com.alibaba.nacos
        nacos-client
    
    
     org.springframework.cloud
     spring-cloud-starter-netflix-ribbon
    
  


  com.alibaba.nacos
  nacos-client
  2.0.3

4、引入spring-cloud-loadbalancer:


	org.springframework.cloud
	spring-cloud-loadbalancer

5、spring-cloud-starter-openfeign中exclude掉ribbon的依赖:


    org.springframework.cloud
    spring-cloud-starter-openfeign
    
        
            org.springframework.cloud
            spring-cloud-netflix-ribbon
        
    

6、application.yml中禁用nacos的ribbon:

ribbon:
  nacos:
    enabled: false

现在的现象:

  • Spring gateway启动不报错;
  • gateway也可以正常注册到Nacos;
  • 通过打断点到NacosDiscoveryClientAutoConfiguration,NacosDiscoveryClient会被初使化,但是调用时不会调用NacosDiscoveryClient.getInstances(String)获取被调用应用的Provider,会报类似下面的接口404错误:

{"msg":"/user-service/user/getByToken","result":404,"data":null}

其中user-service为注册到Nacos上面的服务名称,但是就是不能够被调用到。

  • Spring gateway的注册中心切换为Eureka,再次调用服务时,Eureka的CompositeDiscoveryClient.getInstances(String)方法就会被调用。

二、问题分析

前面走了一些弯路,也花了一些时间,最后想到的是与Eureka注册中心进行对比调试分析,下面例出关键的分析步骤。

Debug断点打到DiscoveryClientRouteDefinitionLocator两个构造函数上,只有参数是ReactiveDiscoveryClient的构造函数被加载:

继续跟踪到ReactiveCompositeDiscoveryClient.getServices()方法:

发现数组变量discoveryClients包含了两个实现,如下图所示:

 

其中有一个是EurekaReactiveDiscoveryClient,那在使用Nacos时就应该包含一个针对Nacos实现的ReactiveDiscoveryClient,于是切换为Nacos分支调试。

但是调用发现数组变量discoveryClients并没有包含针对Nacos实现的ReactiveDiscoveryClient:

于是参考EurekaReactiveDiscoveryClient以及NacosDiscoveryClient,立即就写了NacosReactiveDiscoveryClient:

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.alibaba.nacos.NacosServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;

import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;

import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;

@Slf4j
public class NacosReactiveDiscoveryClient implements ReactiveDiscoveryClient {

	public static final String DEscriptION = "Spring Cloud Nacos Reactive Discovery Client";

	private NacosDiscoveryProperties discoveryProperties;

	public NacosReactiveDiscoveryClient(NacosDiscoveryProperties discoveryProperties) {
		this.discoveryProperties = discoveryProperties;
	}

	@Override
	public String description() {
		return DEscriptION;
	}

	@Override
	public Flux getInstances(String serviceId) {
		try {
			List instances = discoveryProperties.namingServiceInstance().selectInstances(serviceId, true);

			return Flux.fromStream(hostToServiceInstanceList(instances, serviceId).stream());
		} catch (Exception e) {
			throw new RuntimeException("Can not get hosts from nacos server. serviceId: " + serviceId, e);
		}
	}

	@Override
	public Flux getServices() {
		try {
			ListView services = discoveryProperties.namingServiceInstance().getServicesOfServer(1,
					Integer.MAX_VALUE);

			return Flux.fromStream(services.getData().parallelStream());
		} catch (Exception e) {
			log.error("get service name from nacos server fail,", e);
			return Flux.fromStream(Collections.emptyList().stream());
		}
	}

	private static ServiceInstance hostToServiceInstance(Instance instance, String serviceId) {
		NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
		nacosServiceInstance.setHost(instance.getIp());
		nacosServiceInstance.setPort(instance.getPort());
		nacosServiceInstance.setServiceId(serviceId);

		Map metadata = new HashMap<>();
		metadata.put("nacos.instanceId", instance.getInstanceId());
		metadata.put("nacos.weight", instance.getWeight() + "");
		metadata.put("nacos.healthy", instance.isHealthy() + "");
		metadata.put("nacos.cluster", instance.getClusterName() + "");
		metadata.putAll(instance.getmetadata());
		nacosServiceInstance.setmetadata(metadata);

		if (metadata.containsKey("secure")) {
			boolean secure = Boolean.parseBoolean(metadata.get("secure"));
			nacosServiceInstance.setSecure(secure);
		}
		return nacosServiceInstance;
	}

	private static List hostToServiceInstanceList(List instances, String serviceId) {
		List result = new ArrayList<>(instances.size());
		for (Instance instance : instances) {
			result.add(hostToServiceInstance(instance, serviceId));
		}
		return result;
	}

}

并在启动时创建Bean:

 

再次启动调试就可以看到数组变量discoveryClients中有NacosReactiveDiscoveryClient了:

 再次通过网关请求服务,就可以正常调用成功了。

 感觉Nacos的怪问题都让我给碰上了!

 

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/309536.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号