前言:
前面的系列文章让我们对 Nacos 有了一个基本了解,并知道了如何去试用 Nacos 作为注册中心和配置中心,本篇我们将从源码层面去分析 Nacos 的服务注册流程。
Nacos 系列文章传送门:
Nacos 配置管理模型 – 命名空间(Namespace)、配置分组(Group)和配置集ID(Data ID)
服务启动何时触发 Nacos 的注册流程?
想要知道服务是如何注册到 Nacos 的最简单方法就是启动我们的微服务,跟着启动流程走可以了,Spring Boot 项目的启动流程源码之前已经分析过,这里不再详细分析,我们只看跟服务注册有关的核心代码,我们知道 Spring Boot 启动后,会调用到 AbstractApplicationContext#finishRefresh 方法,如下:
//完成后刷新
protected void finishRefresh() {
//清除资源缓存
this.clearResourceCaches();
//初始化生命周期处理器
this.initLifecycleProcessor();
//将刷新完成事件广播到 生命周期处理器
this.getLifecycleProcessor().onRefresh();
//广播容器刷新完成事件
this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
if (!NativeDetector.inNativeImage()) {
//注册 ApplicationContext 到 LiveBeansView 内部的 applicationContexts 中
LiveBeansView.registerApplicationContext(this);
}
}
我们重点关注 this.getLifecycleProcessor().onRefresh() 这行代码,这行代码的作用是将 IOC 容器刷新完成事件广播到生命周期处理器,这里回调处理的众多生命周期处理器中有一个叫做 WebServerStartStopLifecycle 的生命周期处理器,WebServerStartStopLifecycle 中有一个 start 方法,如下:
//org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle#start
public void start() {
this.webServer.start();
this.running = true;
//发布 Web容器初始化完成 事件
this.applicationContext.publishEvent(new ServletWebServerInitializedEvent(this.webServer, this.applicationContext));
}
我们可以看到 start 方法发布了一个 ServletWebServerInitializedEvent 容器初始化完成事件,根据 Spring 的事件发布机制可以知道,肯定会有某个监听器监听了这个事件,我们发现 org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration 这个类监听了 ServletWebServerInitializedEvent 事件,因此一旦发布了 ServletWebServerInitializedEvent 事件,AbstractAutoServiceRegistration 就能马上感知到,并在 AbstractAutoServiceRegistration#onApplicationEvent 方法中进行相应的处理。
AbstractAutoServiceRegistration#onApplicationEvent 方法分析
AbstractAutoServiceRegistration#onApplicationEvent 方法是 WebServerInitializedEvent 事件的回调方法,调用了 AbstractAutoServiceRegistration#bind 方法。
//org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration#onApplicationEvent
public void onApplicationEvent(WebServerInitializedEvent event) {
this.bind(event);
}
AbstractAutoServiceRegistration#bind 方法分析
AbstractAutoServiceRegistration#bind 方法进行简单的判断后继续调用了 AbstractAutoServiceRegistration#start 方法,发起服务注册。
//org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration#bind
@Deprecated
public void bind(WebServerInitializedEvent event) {
//获取 ApplicationContext
ApplicationContext context = event.getApplicationContext();
//判断服务的 namespace
if (!(context instanceof ConfigurableWebServerApplicationContext) || !"management".equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) {
//记录服务端口
this.port.compareAndSet(0, event.getWebServer().getPort());
//发起服务注册
this.start();
}
}
AbstractAutoServiceRegistration#start方法分析
AbstractAutoServiceRegistration#start方法进行简单的判断后继续调用了 AbstractAutoServiceRegistration#start ,调用了 NacosAutoServiceRegistration#register 方法发起服务注册,至此终于出现了 Nacos。
//com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration#register
protected void register() {
//判断是否开启注册
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
log.debug("Registration disabled.");
} else {
if (this.registration.getPort() < 0) {
this.registration.setPort(this.getPort().get());
}
//调用 AbstractAutoServiceRegistration#register 方法
super.register();
}
}
AbstractAutoServiceRegistration#register 方法分析
NacosAutoServiceRegistration#register 方法简单的判断服务是否开启注册后,继续调用了父类 AbstractAutoServiceRegistration#register,父类中的 serviceRegistry 是 NacosServiceRegistry 的一个实例,它是Spring Boot 在 NacosServiceRegistryAutoConfiguration 中自动注入的,最终是调用了 NacosServiceRegistry#register 方法完成服务注册。
//com.alibaba.cloud.nacos.registry.NacosAutoServiceRegistration#register
protected void register() {
//判断是否开启注册
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
log.debug("Registration disabled.");
} else {
if (this.registration.getPort() < 0) {
this.registration.setPort(this.getPort().get());
}
//调用父类 AbstractAutoServiceRegistration#register 方法
super.register();
}
}
//org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration#register
protected void register() {
//调用 NacosServiceRegistry#register 方法完成服务注册
this.serviceRegistry.register(this.getRegistration());
}
NacosServiceRegistryAutoConfiguration 方源码分析
这里直接附上 NacosServiceRegistryAutoConfiguration 源码,我们知道 NacosServiceRegistryAutoConfiguration 类是 Nacos 服务自动注册相关的配置类,是通过 Spring Boot 自动配置加载的,阅读源码,我们发现这个配置类并没有做其他的事情,只是注入了三个类,如下:
- NacosServiceRegistry:完成服务注册功能,实现 ServiceRegistry 接口。
- NacosRegistration:注册时用来存储 Nacos 服务端的相关信息。
- NacosAutoServiceRegistration:真正完成 Nacos 自动注册功能。
package com.alibaba.cloud.nacos.registry;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
import java.util.List;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@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);
}
}
至此,我们基本梳理清楚了 Nacos 的服务注册流程,简单总结如下:
- 服务启动时候通过 Spring Boot 自动配置功能,自动加载了 META-INF/spring.factories中的 Nacos 服务注册的自动配置类 NacosServiceRegistryAutoConfiguration,而 NacosServiceRegistryAutoConfiguration 又往 Spring注入了三个重要的 Bean,NacosServiceRegistry、NacosRegistration、NacosAutoServiceRegistration。
- 服务启动到最后会调用 AbstractApplicationContext#finishRefresh 方法,将 IOC 容器刷新完成事件广播到生命周期处理器,众多生命周期处理器中有一个叫做 WebServerStartStopLifecycle 的生命周期处理器,WebServerStartStopLifecycle 会发布了一个 ServletWebServerInitializedEvent 容器初始化完成事件。
- AbstractAutoServiceRegistration 监听了 WebServerInitializedEvent 事件,执行服务注册。
- NacosAutoServiceRegistration 重写了register 方法,最终会调用 NacosServiceRegistry#register 方法完成服务的自动注册。
总结:服务注册到 Nacos 流程的核心是使用了 Spring 的事件监听机制,虽然 Spring 的监听机制在我们平时写代码中几乎用不到,但是在框架源码中还是大量使用了的。
欢迎提出建议及对错误的地方指出纠正。