主要原因是Gateway没有发现合适的服务
ReactiveCompositeDiscoveryClient.discoveryClients 中如果只有一个或只有SimpleReactiveDiscoveryClient(没有合适服务就会使用这个)那就是有问题的
所以这里需要自己实现一个服务发现即可
如果网关服务启动先可能会导致比较晚发现新的服务,可自行调整一下从Nacos中获取服务实例的时间
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import com.alibaba.nacos.api.naming.utils.NamingUtils;
import javafx.print.Collation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.alibaba.nacos.NacosServiceInstance;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Flux;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
//手动注册一个服务发现
@Slf4j
@Configuration
public class NacosServiceDiscoveryClient implements ReactiveDiscoveryClient {
//Nacos服务器地址
@Value("${spring.cloud.nacos.discovery.server-addr}")
protected String serverAddress;
//Nacos服务使用的命名空间
@Value("${spring.cloud.nacos.discovery.namespace}")
protected String namespace;
//Nacos服务使用的组
@Value("${spring.cloud.nacos.discovery.group:DEFAULT_GROUP}")
protected String group;
//存储已发现的服务
private final Map<String,List<Instance>> serviceInstance;
//Nacos服务器交互Api
private NamingService namingService;
public NacosServiceDiscoveryClient(){
serviceInstance = new ConcurrentHashMap<>();
}
@PostConstruct
private void initiation() throws NacosException {
Properties properties = new Properties();
properties.setProperty("serverAddr", serverAddress);
properties.setProperty("namespace", namespace);
//创建命名管理服务
namingService = NamingFactory.createNamingService(properties);
//查询现有服务
ListView<String> services = namingService.getServicesOfServer(1, Integer.MAX_VALUE);
//获得所有的服务名称并遍历
for(String name : services.getData()){
log.info("Service find from Nacos:{}",name);
//注意订阅的函数,参数不对是查询不到指定微服务名称的实例对象的
//可以追踪com.alibaba.nacos.client.naming.net.NamingProxy.queryList(),这个函数会访问Nacos服务器/nacos/v1/instance/list
//的出来的json会解析,将host的数据转换为instance,如果有变更数据就会触发订阅回调
//com.alibaba.nacos.client.naming.net.NamingProxy.reqApi()里面的callServer()里面可以追踪到最终发送给Nacos的请求,也可以查看返回的json中的host判断是否出问题
//触发回调的地方是com.alibaba.nacos.client.naming.core.HostReactor.processServiceJson()
//com.alibaba.nacos.client.naming.core.HostReactor.updateService() 可以快速查看Naocs返回的json数据
if("DEFAULT_GROUP".equals(group)){
namingService.subscribe(name,this::serviceChange);
}
else{
namingService.subscribe(name,group,this::serviceChange);
}
//获得指定微服务名称的实例对象(实际可以不需要此部,subscribe的回调已经处理了,这里是多余的)
List<Instance> instances = namingService.getAllInstances(name, group);
this.serviceInstance.put(name,instances);
}
}
//微服务变更回调
private void serviceChange(Event event) {
//Nacos的数据
if(event instanceof NamingEvent){
NamingEvent namingEvent = (NamingEvent) event;
//获得微服务名称(带组名的)
String name = namingEvent.getServiceName();
//获得微服务名称
name = NamingUtils.getServiceName(name);
//存储微服务实例对象
this.serviceInstance.put(name,namingEvent.getInstances());
}
}
@Override
public String description() {
//对外描述
return NacosServiceDiscoveryClient.class.getName();
}
//获得微服务实例对象
@Override
public Flux<ServiceInstance> getInstances(String serviceId) {
if(serviceInstance.containsKey(serviceId)){
return Flux.fromStream(serviceInstance.get(serviceId).stream().map(this::convertServiceInstance));
}
return Flux.empty();
}
//转换Nacos回调的实例对象为ServiceInstance
private ServiceInstance convertServiceInstance(Instance instance) {
if(instance instanceof ServiceInstance){
return (ServiceInstance) instance;
}
NacosServiceInstance service = new NacosServiceInstance();
service.setServiceId(instance.getServiceName());
service.setHost(instance.getIp());
service.setPort(instance.getPort());
service.setMetadata(instance.getMetadata());
return service;
}
//获得所有微服务名称
@Override
public Flux<String> getServices() {
return Flux.fromStream(this.serviceInstance.keySet().stream());
}
}
标签:available,service,No,Nacos,nacos,alibaba,import,naming,com
From: https://www.cnblogs.com/code-11/p/17133616.html