前言:
前面的系列文章让我们对 Nacos 有了一个基本了解,并知道了如何去试用 Nacos 作为注册中心和配置中心,本篇我们将从源码层面去分析 Nacos 的服务注册流程。
Nacos 系列文章传送门:
Nacos 初步认识和 Nacos 部署细节
Nacos 配置管理模型 – 命名空间(Namespace)、配置分组(Group)和配置集ID(Data ID)
Nacos 注册中心和配置中心【实战】
服务启动何时触发 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) {//获取 ApplicationContextApplicationContext context = event.getApplicationContext();//判断服务的 namespaceif (!(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() {}@Beanpublic 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 的监听机制在我们平时写代码中几乎用不到,但是在框架源码中还是大量使用了的。
欢迎提出建议及对错误的地方指出纠正。