前言
这一小节来学习一下 Nacos 服务的总体注册流程。
Nacos Server 我们还是使用上一节的 Nacos 源码。另外我们需要新建一个 Spring Boot 项目作为服务向 Nacos 中注册。
入口
我们知道,在配置了 Nacos 地址等相关信息后,在启动项目时,就会自动去 Nacos Server 中注册服务信息。
很显然是通过 Spring Boot 的自动配置来实现的。
我们打开 spring-cloud-starter-alibaba-nacos-discovery 的目录来观察一下:
这一小节,我们的重心在服务注册上。这其中有一个自动配置类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);
}
}
这里有三个类,从上到下是NacosServiceRegistry
、NacosRegistration
、NacosAutoServiceRegistration
。
主要类说明
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
interfaceServiceRegistry
interface- Instrumentation for
RestTemplate
to resolve hostnames usingDiscoveryClient
以上官网针对 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 实现的了。