当前位置: 首页>编程语言>正文

springboot 获取 formData Springboot 获取nacos 注册服务列表

一、springboot启动日志报NacosServiceRegistry

springboot+nacos启动时,log会有一条nacos注册信息如下:

springboot 获取 formData Springboot 获取nacos 注册服务列表,springboot 获取 formData Springboot 获取nacos 注册服务列表_spring,第1张

**很显然,启动注册服务的操作便在NacosServiceRegistry当中。

NacosServiceRegistry可以通过查找所有类直接寻找,也可以从以下springboot自动装配的角度去寻找

通过查看spring.factories文件也可以看到,nacos自动装配的类如下,nacos按照了springboot的约定进行了自动装配:**

springboot 获取 formData Springboot 获取nacos 注册服务列表,springboot 获取 formData Springboot 获取nacos 注册服务列表_自动装配_02,第2张

进入到NacosDiscoveryAutoConfiguration发现,前两个Bean都是作为最后一个Bean的参数,猜想第三个bean是主要的注册方法。

springboot 获取 formData Springboot 获取nacos 注册服务列表,springboot 获取 formData Springboot 获取nacos 注册服务列表_服务端_03,第3张

****点进去发现他继承了AbstractAutoServiceRegistration.class,并且AbstractAutoServiceRegistration.class实现了ApplicationContextAware以及ApplicationListener,果然下方有一个onApplicationEvent的方法

springboot 获取 formData Springboot 获取nacos 注册服务列表,springboot 获取 formData Springboot 获取nacos 注册服务列表_spring_04,第4张

监听器中有一个bind方法,bind方法中又有一个start方法:

public void start() {
        if (!this.isEnabled()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Discovery Lifecycle disabled. Not starting");
            }

        } else {
            if (!this.running.get()) {
                this.context.publishEvent(new InstancePreRegisteredEvent(this, this.getRegistration()));
                this.register();
                if (this.shouldRegisterManagement()) {
                    this.registerManagement();
                }

                this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));
                this.running.compareAndSet(false, true);
            }

        }
    }

其中的register便是注册方法。由此便找到了NacosServiceRegistry.class

二、register剖析

register方法如下:

public void register(Registration registration) {
        if (StringUtils.isEmpty(registration.getServiceId())) {
            log.warn("No service to register for nacos client...");
        } else {
            String serviceId = registration.getServiceId();
            Instance instance = this.getNacosInstanceFromRegistration(registration);

            try {
                this.namingService.registerInstance(serviceId, instance);
                log.info("nacos registry, {} {}:{} register finished", new Object[]{serviceId, instance.getIp(), instance.getPort()});
            } catch (Exception var5) {
                log.error("nacos registry, {} register failed...{},", new Object[]{serviceId, registration.toString(), var5});
            }

        }
    }

2.1 getServiceId查看源码最终发现读取了配置文件的spring项目的name

springboot 获取 formData Springboot 获取nacos 注册服务列表,springboot 获取 formData Springboot 获取nacos 注册服务列表_spring_05,第5张

2.2 getNacosInstanceFromRegistration方法获取了本地客户端的一些信息,然后生成实例

private Instance getNacosInstanceFromRegistration(Registration registration) {
        Instance instance = new Instance();
        instance.setIp(registration.getHost());
        instance.setPort(registration.getPort());
        instance.setWeight((double)this.nacosDiscoveryProperties.getWeight());
        instance.setClusterName(this.nacosDiscoveryProperties.getClusterName());
        instance.setMetadata(registration.getMetadata());
        return instance;
    }

那么注册的主要方法便是this.namingService.registerInstance(serviceId, instance);

2.3 registerInstance方法设置了注册需要的一些基础信息,其中groupname默认为DEFAULT_GROUP

public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
        if (instance.isEphemeral()) {
            BeatInfo beatInfo = new BeatInfo();
            beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));
            beatInfo.setIp(instance.getIp());
            beatInfo.setPort(instance.getPort());
            beatInfo.setCluster(instance.getClusterName());
            beatInfo.setWeight(instance.getWeight());
            beatInfo.setMetadata(instance.getMetadata());
            beatInfo.setScheduled(false);
            long instanceInterval = instance.getInstanceHeartBeatInterval();
            beatInfo.setPeriod(instanceInterval == 0L ? DEFAULT_HEART_BEAT_INTERVAL : instanceInterval);
            this.beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);
        }

        this.serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);
    }

其中最后一行代码执行了注册动作,注册之前会通过schedule的方式添加定时心跳检测任务,默认五秒检测,而且会根据计算机可用资源核心数除以二分配检测资源(最小为1核心数),暂时不看

2.4 registerService方法进行了post请求,将本地的一些基础信息作为参数放入到请求体当中,进行post

public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
        LogUtils.NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}", new Object[]{this.namespaceId, serviceName, instance});
        Map<String, String> params = new HashMap(9);
        params.put("namespaceId", this.namespaceId);
        params.put("serviceName", serviceName);
        params.put("groupName", groupName);
        params.put("clusterName", instance.getClusterName());
        params.put("ip", instance.getIp());
        params.put("port", String.valueOf(instance.getPort()));
        params.put("weight", String.valueOf(instance.getWeight()));
        params.put("enable", String.valueOf(instance.isEnabled()));
        params.put("healthy", String.valueOf(instance.isHealthy()));
        params.put("ephemeral", String.valueOf(instance.isEphemeral()));
        params.put("metadata", JSON.toJSONString(instance.getMetadata()));
        this.reqAPI(UtilAndComs.NACOS_URL_INSTANCE, params, (String)"POST");
    }

最后通过callServer方法中的httpClient进行了http请求,请求地址为http://127.0.0.1:8848/nacos/v1/ns/instance

springboot 获取 formData Springboot 获取nacos 注册服务列表,springboot 获取 formData Springboot 获取nacos 注册服务列表_自动装配_06,第6张

而通过debug执行这一行代码之后,在nacos就能看到服务已经注册了上去。

客户端已经知道注册的流程是怎么样的了,接下来看服务端接收到http请求会有什么样的操作。

三、服务端的处理

上面的http请求地址为http://127.0.0.1:8848/nacos/v1/ns/instance,对应的controller方法为register方法,位置如下:

springboot 获取 formData Springboot 获取nacos 注册服务列表,springboot 获取 formData Springboot 获取nacos 注册服务列表_spring_07,第7张

3.1 点击去之后发现最终的实现方法为registerInstance

public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {
        
        createEmptyService(namespaceId, serviceName, instance.isEphemeral());
        
        Service service = getService(namespaceId, serviceName);
        
        if (service == null) {
            throw new NacosException(NacosException.INVALID_PARAM,
                    "service not found, namespace: " + namespaceId + ", service: " + serviceName);
        }
        
        addInstance(namespaceId, serviceName, instance.isEphemeral(), instance);
    }

首先会去创建一个新的service,namespaceId为键,如果namespaceId不存在,则执行createServiceIfAbsent,服务第一次都会进行这个方法的执行,执行之后会保存在一个叫serviceMap的Map存储结构当中,相当于缓存

public void createEmptyService(String namespaceId, String serviceName, boolean local) throws NacosException {
    createServiceIfAbsent(namespaceId, serviceName, local, null);
}

3.2 接着是addInstance方法,这个方法会根据ip地址

public void addInstance(String namespaceId, String serviceName, boolean ephemeral, Instance... ips)
            throws NacosException {
        
        String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral);
        
        Service service = getService(namespaceId, serviceName);
        
        synchronized (service) {
            List<Instance> instanceList = addIpAddresses(service, ephemeral, ips);
            
            Instances instances = new Instances();
            instances.setInstanceList(instanceList);
            
            consistencyService.put(key, instances);
        }
    }

最后通过consistencyService.put(key, instances);做持久化,并没有持久到数据库当中。

ConsistencyService类会通过添加监听器的方式,当值进行变化时执行onchange方法来更改服务当前状态:



https://www.xamrdz.com/lan/5qf1960367.html

相关文章: