首页 > 其他分享 >Spring boot Gateway 使用Nacos注册中心No servers available for service

Spring boot Gateway 使用Nacos注册中心No servers available for service

时间:2023-02-18 21:12:00浏览次数:34  
标签:available service No Nacos nacos alibaba import naming com

主要原因是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

相关文章