Nacos源码(三):SpringCloud-Nacos客户端注册源码分析
1、服务注册源码入口
在笔记(二):Nacos环境搭建中提到Nacos作为注册中心,在服务启动类中可通过添加可选配置注解@EnableDiscoveryClient,那么就先从这个注解入手,开启SpringCloud的Nacos注册中心的源码分析。
EnableDiscoveryClient注解详情:
EnableDiscoveryClientImportSelector详情:
添加了AutoServicRegistrationConfiguration,详情如下:
1、加载配置类AutoServiceRegistrationProperties
2、判断AutoServicRegistrationConfiguration配置类生效条件,自动注册的属性配置默认为true。
AutoServiceRegistrationProperties、AutoServicRegistrationConfiguration都是spring-cloud-commons包下的,根据SpringBoot自动装配的特性,需要自动装配的内容:spring.factories详情如下:
AutoServiceRegistrationAutoConfiguration详情如下:
在加载AutoServiceRegistrationAutoConfiguration时,需要导入AutoServicRegistrationConfiguration获取默认的配置信息,有个关键的对象属性AutoServiceRegistration。
AutoServiceRegistration接口的实现类如下:
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。
NacosServiceRegistry、NacosRegistration 用来构建 NacosAutoServiceRegistration 的bean。
通过这种方式,也可以获取Nacos注册的核心类 - NacosAutoServiceRegistration。
3、Nacos与Spring的整合
NacosAutoServiceRegistration的类继承关系如下:
NacosAutoServiceRegistration的父类AbstractAutoServiceRegistration实现了ApplicationListener接口。在Spring启动过程中, AbstractApplicationContext#finishRefresh()过程会触发ApplicationListener接口的onApplicationEvent方法,如下:
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、整体流程图
1、SpringBoot自动装配,Nacos注册相关bean做实例化,如 NacosAutoServiceRegistration、NacosServiceRegistry 的实例化;
2、利用Spring的事件,在Spring启动过程中,监听Nacos注册事件,调用 NacosServiceRegistry#registry()方法;
3、创建NamingService、Instance实例,调用Nacos-Client的 NamingClientProxy 注册服务,默认使用gRPC协议注册。