Nacos server: 2.4.3
JDK: 1.8
spring-cloud-starter-alibaba-nacos-discovery-2021.0.5.0.jar
Maven: 3.8.8
我的Nacos仓库:https://github.com/wangyong5609/nacos,分支:2.4.3-analysis
一、Nacos简介
Nacos 是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台

目前主要关注 Nacos 服务注册与发现相关的内容
- 服务提供者在启动时会向Nacos注册中心发送注册请求,包括服务名称、IP地址、端口号等信息。
- Nacos服务端接收到注册请求后,将服务实例信息存储在注册中心的数据库中,并缓存到内存中以便快速查询。
- 注册成功后,服务提供者会定期向Nacos发送心跳请求,以表明服务实例仍在运行中。
- 服务消费者从服务注册中心发现并调用服务。

二、服务注册原理
1.客户端请求原理图
Processon 地址:https://www.processon.com/diagraming/672d9c0ca8011b320f4a064c

简单来说就是,项目引入 spring-cloud-starter-alibaba-nacos-discovery 以后,利用Spring的自动装配,在它的spring.facotries中加载了 NacosServiceRegistryAutoConfiguration, NacosServiceRegistryAutoConfiguration 中加载了一个叫 NacosAutoServiceRegistration 的Bean,
这个Bean的父类实现了 ApplicationListener 这个接口,并监听了WebServerInitializedEvent类型的事件,在Tomcat启动后会发布WebServerInitializedEvent的事件,事件被监听到以后,就会调用 NacosServiceRegistry的 register 方法向Nacos服务端注册实例,临时实例使用 RPC 调用,永久实例使用 HTTP 调用。
2.服务端处理请求原理图
Processon 地址:https://www.processon.com/diagraming/67301240be9d2e22e50d3a19

注册临时实例:
RequestHandlerRegistry监听了ContextRefreshedEvent事件,在 Springboot 启动时context初始化完成后,通知RequestHandlerRegistry开始注册RequestHandler的全部实现类,这里面就包括InstanceRequestHandler。
注册实例的 grpc 请求会被GrpcRequestAcceptor接口, 从RequestHandlerRegistry中拿到InstanceRequestHandler处理实例注册请求,然后调用EphemeralClientOperationServiceImpl.registerInstance() , 发布客户端注册事件ClientRegisterServiceEvent.
注册永久实例:
在Springboot 启动时会加载BeanPersistentClientOperationServiceImpl,初始化CPProtocol, 创建 NacosStateMachine, 并向状态机注册请求处理器EphemeralClientOperationServiceImpl, 启动RaftServer集群。
注册实例的 HTTP 请求进入InstanceController的register方法,然后调用EphemeralClientOperationServiceImplde的registerInstance()方法,提交注册请求给 raft 集群,集群会让 Leader 节点处理本次写操作,最终会由状态机注册的processor也就是EphemeralClientOperationServiceImpl处理,调用它的onApply方法,发布客户端注册事件ClientRegisterServiceEvent.
处理客户端注册事件
监听客户端注册事件的ClientServiceIndexesManager收到通知以后,将实例信息保存到本地注册表,并发布ServiceChangedEvent事件通知其他客户端,
NamingSubscriberServiceV2Impl监听到ServiceChangedEvent发布后,创建信息推送任务,添加到延迟任务执行引擎PushDelayTaskExecuteEngine, 引擎执行推送任务。
三、源码分析
客户端
当我们服务引入spring-cloud-starter-alibaba-nacos-discovery,便可以实现自动进行注册,这是因为在spring.facotries中自动装配了NacosServiceRegistryAutoConfiguration

1. NacosServiceRegistryAutoConfiguration加载Bean

此类中定义了三个 Bean:NacosServiceRegistry, NacosRegistration , NacosAutoServiceRegistration
仔细看会发现,前面两个Bean 都是 NacosAutoServiceRegistration 的入参
1.1 NacosServiceRegistry
NacosServiceRegistry 的构造函数入参主要是一些注册需要的配置信息,下面的register 方法就是实现服务注册的,不过要想在服务启动时自动完成注册,还得靠 NacosAutoServiceRegistration

1.2 NacosRegistration
registrationCustomizers:一个NacosRegistrationCustomizer类型的列表,可能用于自定义注册过程。nacosDiscoveryProperties:包含 Nacos 服务发现的相关配置。context:ApplicationContext类型的对象,表示 Spring 应用上下文,可能用于访问 Spring 框架的功能。

1.3 NacosAutoServiceRegistration

这里我在查看类图的时候,图中并不显示
NacosAutoServiceRegistration,而是从它的父类开始展示,没找到在哪里可以配置。不过可以按空格添加这个进来,也算是个办法。
从类图中可以看到实现了 ApplicationListener 接口,这是实现自动注册的关键。

2. 监听WEB容器事件
ApplicationListener 是 Spring 框架中一个接口,它属于 org.springframework.context 包。这个接口允许 beans 监听 Spring 事件发布系统发布的事件。

WebServerInitializedEvent 是 Spring Boot 中的一个具体事件类,它属于 org.springframework.boot.web.context 包,继承自ApplicationEvent。这个事件在嵌入式 web 服务器(如 Tomcat、Jetty 或 Undertow)初始化完成后发布。
当你创建一个 ApplicationListener 的实现,并指定 WebServerInitializedEvent 作为泛型参数时,Spring 容器会自动调用你的 onApplicationEvent 方法,并将 WebServerInitializedEvent 的实例作为参数传递给你的 listener。

SmartLifecycle 是一个接口,它继承自 Lifecycle 接口,允许细粒度的控制Bean的生命周期行为。
start方法在Tomcat容器启动后,发布事件 ServletWebServerInitializedEvent, ServletWebServerInitializedEvent 继承自WebServerInitializedEvent

3. 处理容器事件
所以当容器初始化完成后,会调用 org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration#onApplicationEvent

// org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration#start
public void start() {
// 配置:spring.cloud.nacos.discovery.enabled
if (!this.isEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Discovery Lifecycle disabled. Not starting");
}
} else {
// 是否已启动
if (!this.running.get()) {
// 发布预注册事件
this.context.publishEvent(new InstancePreRegisteredEvent(this, this.getRegistration()));
// 开始注册
this.register();
if (this.shouldRegisterManagement()) {
this.registerManagement();
}
// 发布注册后事件
this.context.

最低0.47元/天 解锁文章
2127

被折叠的 条评论
为什么被折叠?



