Nacos源码(一)客户端注册

本文详细解释了SpringBoot应用如何利用Nacos进行服务注册,涉及NacosServiceRegistryAutoConfiguration的配置和NacosServiceRegistry处理服务注册及心跳任务的实现过程。
摘要由CSDN通过智能技术生成

本文主题

  1. 客户端如何注册
  2. 服务端怎么找对应的代码

1、客户端如何注册

这里我们可以利用SpringBoot的自动装配搜索一下Nacos的自动配置类
就会搜索到这个这么个玩意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<List<NacosRegistrationCustomizer>> 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);
    }
}

这里我们发现自动类,创建了三个类,并把俩个自动类封装到这个NacosAutoServiceRegistration这个类里,说明这个类就是核心

1.1、NacosAutoServiceRegistration初始化

这里我们首先进入这个类的类图
image.png
我们会发现这个类继承了ApplicationLIstener这个类说明他会处理事件,那么我们看一下这个类的构造方法

public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
    super(serviceRegistry, autoServiceRegistrationProperties);
    this.registration = registration;
}


// 父类
protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry, AutoServiceRegistrationProperties properties) {
        this.serviceRegistry = serviceRegistry;
        this.properties = properties;
}

这里我们会发现构造方法并没有处理什么,那么只有处理事件了

1.2、�NacosAutoServiceRegistration处理容器启动完毕事件

注意:这里NacosAutoServiceREgistration并没有处理事件,而是他的父类AbstractAutoServiceRegistration处理的
父类处理(AbstractAutoServiceRegistration):

public void onApplicationEvent(WebServerInitializedEvent event) {
    this.bind(event);
}

public void bind(WebServerInitializedEvent event) {
    ApplicationContext context = event.getApplicationContext();
    if (!(context instanceof ConfigurableWebServerApplicationContext) || !"management".equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) {
        this.port.compareAndSet(0, event.getWebServer().getPort());
        // 启动
        this.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);
        }

    }
}

protected void register() {
    // 核心,还记得我们创建的NacosAutoServiceRegistration的时候会传递俩个对象进来
    // 其中serviceRegistry就是NacosServiceRegistry
    this.serviceRegistry.register(this.getRegistration());
}

�那么这里就跳到了NacosServiceRegistry来处理注册了

1.3、NacosServiceRegistry处理注册

public void register(Registration 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 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);
        }

    }
}

这里没有什么东西,就是把配置生成一个Instance对象,这里我们往下看

public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    NamingUtils.checkInstanceIsLegal(instance);
    
    // 这里其实就是 groupedServiceName = groupName + "@@" + serviceName;
    String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
    // 判断实例是否是临时实例,默认创建出来的instance就是临时实例
    if (instance.isEphemeral()) {
        // 构造一个心跳信息
        BeatInfo beatInfo = this.beatReactor.buildBeatInfo(groupedServiceName, instance);
        // 创建一个心跳任务
        this.beatReactor.addBeatInfo(groupedServiceName, beatInfo);
    }

    // 继续调用注册
    this.serverProxy.registerService(groupedServiceName, groupName, instance);
}

这里就干了俩件事,创建一个心跳任务,继续调用注册http请求,这里我们先看一下心跳

1.4、客户端构造心跳任务

这个是构造心跳信息

public BeatInfo buildBeatInfo(String groupedServiceName, Instance instance) {
    BeatInfo beatInfo = new BeatInfo();
    beatInfo.setServiceName(groupedServiceName);
    beatInfo.setIp(instance.getIp());
    beatInfo.setPort(instance.getPort());
    beatInfo.setCluster(instance.getClusterName());
    beatInfo.setWeight(instance.getWeight());
    beatInfo.setMetadata(instance.getMetadata());
    beatInfo.setScheduled(false);
    // 默认5s
    beatInfo.setPeriod(instance.getInstanceHeartBeatInterval());
    return beatInfo;
}


这个是发送心跳

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);
    // 注意这个BeatTask 就是心跳任务,每隔5s执行一次
    this.executorService.schedule(new BeatReactor.BeatTask(beatInfo), beatInfo.getPeriod(), TimeUnit.MILLISECONDS);
    MetricsMonitor.getDom2BeatSizeMonitor().set((double)this.dom2Beat.size());
}


// 心跳任务
public void run() {
    if (!this.beatInfo.isStopped()) {
        long nextTime = this.beatInfo.getPeriod();

        try {
            // 这里就是发送心跳,利用Http发送心跳
            // 发送到put请求 /nacos/v1/ns/instance/beat  
            // 核心代码
            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);
    }
}
}

�这里就是干了这么一件事
发送到put请求 /nacos/v1/ns/instance/beat

这里我们再回到发送任务

1.5、客户端发送

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(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()));
    // /nacos/v1/ns/instance
    this.reqApi(UtilAndComs.nacosUrlInstance, params, "POST");
}


这里就是访问/instance

1.6、流程图

image.png
image.png

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值