『Naocs 2.x』(二) Spring Cloud 服务发起注册流程

641 阅读3分钟

前言

这一小节来学习一下 Nacos 服务的总体注册流程。

Nacos Server 我们还是使用上一节的 Nacos 源码。另外我们需要新建一个 Spring Boot 项目作为服务向 Nacos 中注册。

入口

我们知道,在配置了 Nacos 地址等相关信息后,在启动项目时,就会自动去 Nacos Server 中注册服务信息。

很显然是通过 Spring Boot 的自动配置来实现的。

我们打开 spring-cloud-starter-alibaba-nacos-discovery 的目录来观察一下:

image-20210629220205383

这一小节,我们的重心在服务注册上。这其中有一个自动配置类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 {
 
    @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(registrationCustomizers.getIfAvailable(),
                nacosDiscoveryProperties, context);
    }
 
    @Bean
    @ConditionalOnBean(AutoServiceRegistrationProperties.class)
    public NacosAutoServiceRegistration nacosAutoServiceRegistration(
            NacosServiceRegistry registry,
            AutoServiceRegistrationProperties autoServiceRegistrationProperties,
            NacosRegistration registration) {
        return new NacosAutoServiceRegistration(registry,
                autoServiceRegistrationProperties, registration);
    }
 
}

这里有三个类,从上到下是NacosServiceRegistryNacosRegistrationNacosAutoServiceRegistration

主要类说明

NacosServiceRegistry

NacosServiceRegistry 实现了 ServiceRegistry<R extends Registration>接口。

ServiceRegistry 接口内定义了服务注册、取消注册、设置状态等方法。我们关注的还是服务注册方法。

既然 NacosServiceRegistry实现了 ServiceRegistry接口,那么它里面就应当定义了 Nacos 具体注册的逻辑。

NacosRegistration

NacosRegistration实现了Registration接口,但Registration接口没有定义方法。

我们可以看到上面的ServiceRegistry泛型就是这个接口,所以此接口表示需要注册的对象,即 NacosRegistration 中包含了服务名称、IP端口等信息。

NacosAutoServiceRegistration

NacosAutoServiceRegistration 实现了 AbstractAutoServiceRegistration<R extends Registration> 接口,其中定义了自动注册的逻辑。

Spring cloud commons

我们发现,自动注册配置的每一个类都实现了其他的某些接口,经过查看,这些接口都来自于Spring cloud commons项目。

Spring Cloud Commons 以两个库的形式提供特性:Spring Cloud Context 和 Spring Cloud Commons。

Spring Cloud Context 为 Spring Cloud 应用程序的 ApplicationContext(引导上下文、加密、刷新范围和环境端点)提供实用程序和特殊服务。

Spring Cloud Commons 是一组抽象和公共类,用于不同的Spring Cloud实现(例如Spring Cloud Netflix 和Spring Cloud Consul)。

Spring Cloud Commons features:

  • DiscoveryClient interface
  • ServiceRegistry interface
  • Instrumentation for RestTemplate to resolve hostnames using DiscoveryClient

以上官网针对 Spring Cloud Commons 项目的说明。

那么用大白话来说,Spring Cloud 定义了一套服务注册和服务发现的接口,想要和 Spring Cloud 做适配的注册中心,就去实现这一套接口,填充里面的逻辑。

AbstractAutoServiceRegistration

这是个自动配置的核心抽象类,我们主要分析这个类。

首先,我们来看这个类的定义。

这个类实现了三个接口:

  • AutoServiceRegistration:这是个标记接口,无方法。标志这个接口的实现类是服务自动注册类。
  • ApplicationContextAware: 这个是 Spring Boot 的扩展接口,通过这个接口,我们可以获取 Spring 的上下文。
  • ApplicationListener: 监听器,监听的时间为WebServerInitializedEvent
public abstract class AbstractAutoServiceRegistration<R extends Registration>
        implements AutoServiceRegistration, ApplicationContextAware,
        ApplicationListener<WebServerInitializedEvent> {
      ....
    }

有那么点感觉了,所以自动注册是怎么做的呢?监听器监听 WebServerInitializedEvent,当环境已初始化完成的时候,就会调用本监听器了。

public void bind(WebServerInitializedEvent event) {
        ApplicationContext context = event.getApplicationContext();
        if (context instanceof ConfigurableWebServerApplicationContext) {
            if ("management".equals(((ConfigurableWebServerApplicationContext) context)
                    .getServerNamespace())) {
                return;
            }
        }
        this.port.compareAndSet(0, event.getWebServer().getPort());
        this.start();
    }

调用了 start()方法:

public void start() {
        if (!isEnabled()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Discovery Lifecycle disabled. Not starting");
            }
            return;
        }
 
        // only initialize if nonSecurePort is greater than 0 and it isn't already running
        // because of containerPortInitializer below
        if (!this.running.get()) {
            this.context.publishEvent(
                    new InstancePreRegisteredEvent(this, getRegistration()));
            register();
            if (shouldRegisterManagement()) {
                registerManagement();
            }
            this.context.publishEvent(
                    new InstanceRegisteredEvent<>(this, getConfiguration()));
            this.running.compareAndSet(false, true);
        }
 
    }

这里调用了register();方法,并且前后各自发布了一个事件。

register()

protected void register() {
        this.serviceRegistry.register(getRegistration());
    }
 
protected abstract R getRegistration();

这里的getRegstration()就由 NacosAutoServiceRegistration,然后返回了 NacosRegistration

总体流程小结

那么我们目光再次回到 spring-cloud-starter-alibaba-nacos-discovery,它在服务注册这块做了什么?

其实就是,实现了 Spring Cloud Commons 定义的,服务注册相关的接口。

简单地总结,Spring Cloud Commons 的AbstractAutoServiceRegistration监听了WebServerInitializedEvent事件,当项目启动初始化完成时,就调用注册方法,进行服务注册。至于具体的注册逻辑,那就是由 spring-cloud-starter-alibaba-nacos-discovery 实现的了。