一、问题描述
我们现在是在用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依赖:
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-alibaba-nacos-discovery</artifactid>
<version>0.9.0.release</version>
<exclusions>
<exclusion>
<groupid>com.alibaba.nacos</groupid>
<artifactid>nacos-client</artifactid>
</exclusion>
<exclusion>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-netflix-ribbon</artifactid>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupid>com.alibaba.nacos</groupid>
<artifactid>nacos-client</artifactid>
<version>2.0.3</version>
</dependency>4、引入spring-cloud-loadbalancer:
<dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-loadbalancer</artifactid> </dependency>
5、spring-cloud-starter-openfeign中exclude掉ribbon的依赖:
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-openfeign</artifactid>
<exclusions>
<exclusion>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-netflix-ribbon</artifactid>
</exclusion>
</exclusions>
</dependency>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;
/**
*
* @author fenglibin
*
*/
@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<serviceinstance> getinstances(string serviceid) {
try {
list<instance> 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<string> getservices() {
try {
listview<string> 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.<string>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<string, string> 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<serviceinstance> hosttoserviceinstancelist(list<instance> instances, string serviceid) {
list<serviceinstance> result = new arraylist<>(instances.size());
for (instance instance : instances) {
result.add(hosttoserviceinstance(instance, serviceid));
}
return result;
}
}或者集成如下starter:
<dependency>
<groupid>com.eeeffff</groupid>
<artifactid>nacos-reactive-discovery-client</artifactid>
<version>1.0.0</version>
</dependency>并在启动时创建bean:

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

再次通过网关请求服务,就可以正常调用成功了。
感觉nacos的怪问题都让我给碰上了!
到此这篇关于spring gateway集成 nacos注册中心不能够发现服务的解决方案的文章就介绍到这了,更多相关spring gateway集成 nacos内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论