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

Nacos:服务注册源码浅析

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

Nacos:服务注册源码浅析

nacos服务注册源码分析,分为nacos客户端和服务端代码,下面先看客户端代码的简单分析

spring-cloud-starter-alibaba-nacos-discovery该starter下面spring.factories文件的内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
  com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,
  com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,
  com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,
  com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,
  com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,
  com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,
  com.alibaba.cloud.nacos.NacosServiceAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=
  com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration
客户端服务注册流程

根据这个配置,我们可以知道引入该starter之后会自动注入那些类,根据名称推测服务注册的配置信息在com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration这个类中,

@Configuration(
    proxyBeanMethods = false
)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(
    value = {"spring.cloud.service-registry.auto-registration.enabled"},
    matchIfMissing = true
)
@AutoConfigureAfter({AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class, NacosDiscoveryAutoConfiguration.class})
public class NacosServiceRegistryAutoConfiguration {
    public NacosServiceRegistryAutoConfiguration() {
    }

    @Bean
    public NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
        return new NacosServiceRegistry(nacosDiscoveryProperties);
    }

    @Bean
    @ConditionalOnBean({AutoServiceRegistrationProperties.class})
    public NacosRegistration nacosRegistration(ObjectProvider> registrationCustomizers, NacosDiscoveryProperties nacosDiscoveryProperties, ApplicationContext context) {
        return new NacosRegistration((List)registrationCustomizers.getIfAvailable(), nacosDiscoveryProperties, context);
    }

    @Bean
    @ConditionalOnBean({AutoServiceRegistrationProperties.class})
    public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
        return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration);
    }
}

这里主要是注入了三个bean实例,我们重点关注NacosServiceRegistry,而该类实现了org.springframework.cloud.client.serviceregistry.ServiceRegistry这个接口:

public interface ServiceRegistry {
    void register(R var1);

    void deregister(R var1);

    void close();

    void setStatus(R var1, String var2);

     T getStatus(R var1);
}

   该接口主要定义了服务注册相关的规范,我们主要关注NacosServiceRegistry中register方法实现:

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

            try {
                // 服务注册
                namingService.registerInstance(serviceId, group, instance);
                log.info("nacos registry, {} {} {}:{} register finished", new Object[]{group, serviceId, instance.getIp(), instance.getPort()});
            } catch (Exception var7) {
                log.error("nacos registry, {} register failed...{},", new Object[]{serviceId, registration.toString(), var7});
                ReflectionUtils.rethrowRuntimeException(var7);
            }

        }
    }

可以发现,服务注册是通过NamingService来完成的:

namingService.registerInstance(serviceId, group, instance);

来到NacosNamingService#registerInstance

    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
        NamingUtils.checkInstanceIsLegal(instance);
        String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
        // 默认为true
        if (instance.isEphemeral()) {
            // 构建心跳信息
            BeatInfo beatInfo = this.beatReactor.buildBeatInfo(groupedServiceName, instance);
            // 发送心跳
            this.beatReactor.addBeatInfo(groupedServiceName, beatInfo);
        }
        // 执行服务注册
        this.serverProxy.registerService(groupedServiceName, groupName, instance);
    }

先看服务注册:

        // 执行服务注册
        this.serverProxy.registerService(groupedServiceName, groupName, instance);

 来到NamingProxy#registerService

    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 params = new HashMap(16);
        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", JacksonUtils.toJson(instance.getmetadata()));
        this.reqApi(UtilAndComs.nacosUrlInstance, params, "POST");
    }

这里跟踪代码会发现,就是通过post请求/nacos/v1/ns/instance进行服务注册的

在来看下发送心跳的细节:

// 发送心跳
this.beatReactor.addBeatInfo(groupedServiceName, beatInfo);

来到BeatReactor#addBeatInfo

    public void addBeatInfo(String serviceName, BeatInfo beatInfo) {
        LogUtils.NAMING_LOGGER.info("[BEAT] adding beat: {} to beat map.", beatInfo);
        String key = this.buildKey(serviceName, beatInfo.getIp(), beatInfo.getPort());
        BeatInfo existBeat = null;
        if ((existBeat = (BeatInfo)this.dom2Beat.remove(key)) != null) {
            existBeat.setStopped(true);
        }

        this.dom2Beat.put(key, beatInfo);
        // 通过线程池来执行发送心跳的任务 
        this.executorService.schedule(new BeatReactor.BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS);
        MetricsMonitor.getDom2BeatSizeMonitor().set((double)this.dom2Beat.size());
    }

我们重点看BeatTask的实现,它是BeatReactor的一个内部类:

    class BeatTask implements Runnable {
        BeatInfo beatInfo;

        public BeatTask(BeatInfo beatInfo) {
            this.beatInfo = beatInfo;
        }

        public void run() {
            if (!this.beatInfo.isStopped()) {
                long nextTime = this.beatInfo.getPeriod();

                try {
                    JsonNode result = BeatReactor.this.serverProxy.sendBeat(this.beatInfo, BeatReactor.this.lightBeatEnabled);
                    long interval = result.get("clientBeatInterval").asLong();
                    boolean lightBeatEnabled = false;
                    if (result.has("lightBeatEnabled")) {
                        lightBeatEnabled = result.get("lightBeatEnabled").asBoolean();
                    }

                    BeatReactor.this.lightBeatEnabled = lightBeatEnabled;
                    if (interval > 0L) {
                        nextTime = interval;
                    }

                    int code = 10200;
                    if (result.has("code")) {
                        code = result.get("code").asInt();
                    }

                    if (code == 20404) {
                        Instance instance = new Instance();
                        instance.setPort(this.beatInfo.getPort());
                        instance.setIp(this.beatInfo.getIp());
                        instance.setWeight(this.beatInfo.getWeight());
                        instance.setmetadata(this.beatInfo.getmetadata());
                        instance.setClusterName(this.beatInfo.getCluster());
                        instance.setServiceName(this.beatInfo.getServiceName());
                        instance.setInstanceId(instance.getInstanceId());
                        instance.setEphemeral(true);

                        try {
                            BeatReactor.this.serverProxy.registerService(this.beatInfo.getServiceName(), NamingUtils.getGroupName(this.beatInfo.getServiceName()), instance);
                        } catch (Exception var10) {
                            ;
                        }
                    }
                } catch (NacosException var11) {
                    LogUtils.NAMING_LOGGER.error("[CLIENT-BEAT] failed to send beat: {}, code: {}, msg: {}", new Object[]{JacksonUtils.toJson(this.beatInfo), var11.getErrCode(), var11.getErrMsg()});
                }

                BeatReactor.this.executorService.schedule(BeatReactor.this.new BeatTask(this.beatInfo), nextTime, TimeUnit.MILLISECONDS);
            }
        }
    }

其逻辑大致如下:

(1)发送心跳给nacos服务器

(2)如果服务返回的clientBeatInterval大于0,则更新调度任务的间隔时间

(3)如果服务返回的code为20404,则发起服务注册请求

(4)重新调度,循环执行(1)(2)(3),直到BeatInfo的stopped属性为true

补充说明:NacosServiceRegistry中register方法的触发时机

服务注册的触发时机是WebServerInitializedEvent事件发布时执行的,因为org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration实现了ApplicationListener接口,进而监听了WebServerInitializedEvent事件。而NacosAutoServiceRegistration又继承了AbstractAutoServiceRegistration,所以可以在WebServerInitializedEvent事件发布时执行服务注册。

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

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

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