Nacos源码(三):SpringCloud-Nacos客户端注册源码分析

发布时间 2023-11-29 10:10:04作者: 无虑的小猪

1、服务注册源码入口

  在笔记(二):Nacos环境搭建中提到Nacos作为注册中心,在服务启动类中可通过添加可选配置注解@EnableDiscoveryClient,那么就先从这个注解入手,开启SpringCloud的Nacos注册中心的源码分析。

  EnableDiscoveryClient注解详情:

0

  EnableDiscoveryClientImportSelector详情:

  添加了AutoServicRegistrationConfiguration,详情如下:

0

  1、加载配置类AutoServiceRegistrationProperties

  2、判断AutoServicRegistrationConfiguration配置类生效条件,自动注册的属性配置默认为true。

   AutoServiceRegistrationProperties、AutoServicRegistrationConfiguration都是spring-cloud-commons包下的,根据SpringBoot自动装配的特性,需要自动装配的内容:spring.factories详情如下:

0

  AutoServiceRegistrationAutoConfiguration详情如下:

   在加载AutoServiceRegistrationAutoConfiguration时,需要导入AutoServicRegistrationConfiguration获取默认的配置信息,有个关键的对象属性AutoServiceRegistration。

  AutoServiceRegistration接口的实现类如下:

0

  NacosAutoServiceRegistration是Nacos注册的核心。

2、SpringBoot自动装配Nacos注册所需Bean

  Nacos的服务注册功能,需要添加如下依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

  找到spring-cloud-starter-alibaba-nacos-discovery依赖中的自动装配文件META-INF/spring.factories文件。

  SpingBoot的自动装配首先会来加载EnableAutoConfiguration对应的类,找到含有"Auto"关键字,因为要了解客户端的服务注册,所以目标类可以锁定在 NacosServiceRegistryAutoCofiguration 类中。

   NacosServiceRegistryAutoCofiguration 中的bean在Spring容器启动时自动注入,其中最核心的是NacosAutoServiceRegistration。

0

  NacosServiceRegistry、NacosRegistration 用来构建 NacosAutoServiceRegistration 的bean。

  通过这种方式,也可以获取Nacos注册的核心类 - NacosAutoServiceRegistration。

3、Nacos与Spring的整合

  NacosAutoServiceRegistration的类继承关系如下:

0

  NacosAutoServiceRegistration的父类AbstractAutoServiceRegistration实现了ApplicationListener接口。在Spring启动过程中,            AbstractApplicationContext#finishRefresh()过程会触发ApplicationListener接口的onApplicationEvent方法,如下:

0

  AbstractAutoServiceRegistration#onApplicationEvent 方法,详情如下:

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();
    }
}

  AbstractAutoServiceRegistration#start 调用注册服务方法:

public void start() {
    // ...
    // Nacos服务注册
    this.register();
    // ...
}

private final ServiceRegistry<R> serviceRegistry;
// 注册服务
protected void register() {
    this.serviceRegistry.register(this.getRegistration());
}

  ServiceRegistry是一个接口,具体的实现类是哪个呢? ServiceRegistry 在 NacosAutoServiceRegistration 有参构造器中被初始化的,这里要看下 NacosServiceRegistryAutoCofiguration 中 NacosAutoServiceRegistration 是如何被实例化的。

@AutoConfigureAfter({AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class, NacosDiscoveryAutoConfiguration.class})
public class NacosServiceRegistryAutoConfiguration {
    public NacosServiceRegistryAutoConfiguration() {
    }
    
    // 实际注册的bean
    @Bean
    public NacosServiceRegistry nacosServiceRegistry(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties nacosDiscoveryProperties) {
        return new NacosServiceRegistry(nacosServiceManager, nacosDiscoveryProperties);
    }
    
    // Nacos信息,包含Nacos地址、心跳间隔、心跳超时时间、IP移除超时时间等
    @Bean
    @ConditionalOnBean({AutoServiceRegistrationProperties.class})
    public NacosRegistration nacosRegistration(ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers, NacosDiscoveryProperties nacosDiscoveryProperties, ApplicationContext context) {
        return new NacosRegistration((List)registrationCustomizers.getIfAvailable(), nacosDiscoveryProperties, context);
    }
    
    // 该bean利用Spring的事件,完成Naocs服务注册
    @Bean
    @ConditionalOnBean({AutoServiceRegistrationProperties.class})
    public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
        return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration);
    }
}

  通过 NacosServiceRegistryAutoCofiguration 中装配的bean,我们知道 NacosServiceRegistry 是 AbstractAutoServiceRegistration 中 ServiceRegistry 属性的实现类。

  服务注册的的调用,NacosServiceRegistry#register 详情如下:

public void register(Registration registration) {
    // ...
    // 获取NamingService服务
    NamingService namingService = this.namingService();
    String serviceId = registration.getServiceId();
    String group = this.nacosDiscoveryProperties.getGroup();
    // 构建instance实例
    Instance instance = this.getNacosInstanceFromRegistration(registration);
    // ...
    // 向服务端注册服务
    namingService.registerInstance(serviceId, group, instance);
    // ...            
}

4、整体流程图

0

  1、SpringBoot自动装配,Nacos注册相关bean做实例化,如 NacosAutoServiceRegistration、NacosServiceRegistry 的实例化;

  2、利用Spring的事件,在Spring启动过程中,监听Nacos注册事件,调用 NacosServiceRegistry#registry()方法;

  3、创建NamingService、Instance实例,调用Nacos-Client的 NamingClientProxy 注册服务,默认使用gRPC协议注册。