文章目录

  • Nacos服务注册原理源码
  • 客户端
  • 服务注册测试单元
  • Nacos自动装配
  • 服务注册
  • 服务端
  • 服务注册
  • 集群同步



Nacos服务注册原理源码

客户端

服务注册测试单元

我们先看一下Nacos客户端给出的服务注册的测试单元代码

nacos 注册到dubbo_服务端

测试单元中主要做的事情:

  1. 构建服务Instance对象
  2. 通过工厂创建NamingService对象
  3. Instance向NamingService(注册中心)注册
  4. 通过serviceName向注册中心(NamingService)获取实例列表信息

测试单元中我们知道客户端根据服务的ip、端口、权重、元数据等参数构建了一个Instance的注册实例对象,

然后根据NacosFactory通过给定的配置创建了一个NamingService,通过NacosFactory#createNamingService代码,可以看到实际上是通过反射创建了NacosNamingService

nacos 注册到dubbo_服务端_02

接下来我们来看下注册实例的代码

nacos 注册到dubbo_服务端_03

registerInstance是个重载方法,另一个registerInstance方法给服务指定了默认的groupName,通过代码可以看到注册方法调用的具体对象是clientProxy,具体类型为NamingClientProxyDelegate,该对象在NamingService#init方法中进行的赋值操作。

我们看下该方法调用代码,首先根据实例是否临时实例,判断注册请求是通过grpc还是http闹到客户端代理对象来注册(实例默认就是临时实例),所以这里会通过grpc对应类型来进行服务注册,可以看到先构建了服务注册请求实例InstanceRequest,然后去向注册中心请求,具体的请求我们就不看了。

nacos 注册到dubbo_服务端_04

nacos 注册到dubbo_java_05

下面我们看下在微服务中,服务是如何自动注册出的,其实我们可以猜测一下,应该是微服务启动过程中,发布了某一个事件,事件监听器监听到该事件后,就开始调用服务注册代码进行注册工作。

Nacos自动装配

<!-- 文中使用的阿里巴巴服务发现版本 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.5.RELEASE</version> </dependency>

我们先找到自动装配的核心类NacosServiceRegistryAutoConfiguration

nacos 注册到dubbo_客户端_06

点进去发现NacosServiceRegistryAutoConfiguration里面注入了三个Bean,分别为NacosServiceRegistry、NacosRegistration、NacosAutoServiceRegistration

nacos 注册到dubbo_自动装配_07

服务注册

NacosServiceRegistry 该类实现了具体的注册逻辑,后面我们可以看到,大家先记住它,还有NacosAutoServiceRegistration也很重要,该类可以说是服务启动后,触发服务注册的入口,我们先看下它的类图

nacos 注册到dubbo_java_08

通过类图我们发现该类继承了AbstractAutoServiceRegistration而父类又实现了ApplicationListener接口,所以它是个监听类,作为监听类肯定有监听方法,监听方法应该就是我们服务注册的入口,事件监听方法存在父类AbstractAutoServiceRegistration`中

WebServerInitializedEvent该事件在容器完成刷新工作后发布的,具体方法为ServletWebServerApplicationContext#finishRefresh

nacos 注册到dubbo_服务端_09

通过方法参数我们知道监听事件为WebServerInitializedEvent,字面意思是web服务初始化后事件,而且可以看到监听方法中还调用用bind方法,bind方法调用的是start方法。我们看下start的具体逻辑

nacos 注册到dubbo_nacos 注册到dubbo_10

该方法中,终于能看到注册相关的代码了,通过断点我们能看到确实走这里的代码了,我们看下该方法能不能找到我们前面说的测试类中的服务注册相关代码,经过一些方法链调用,最终会调到NacosServiceRegistry#register方法中,该类也是我们之前自动装配类中添的,我让大家记住的那个类,该方法中我们能看到之前Nacos官方提供的注册中心客户端注册的测试单元方法中具体的注册方法。

文章中阿里巴巴服务发现版本依赖的是nacos-client1.4.1,目前最新的阿里巴巴服务发现版本2021.1依赖的都是nacos-client1.4.1,而官方提供的测试单元中,是用的nacos-client2.0.0的代码,2.0.0加入了grpc的调用,1.4.1这里使用的是http来调用的,NacosServiceRegistry#register点进去看到的和我们上面的代码不一样。不要等下看到代码不一样,都不知道咋回事。

nacos 注册到dubbo_服务端_11

到此微服务中接口Nacos作为服务注册中心就说完了,下面我们看服务端的接收服务注册具体是咋实现的。

服务端

服务注册

服务端注册处理方法其实挺好找的,毕竟有相关handler InstanceRequestHandler,该handler 包含了服务注册、服务注销,我们服务注册的方法为InstanceRequestHandler#handle,我们先看下该方法代码:

通过请求参数先生成了Service对象,然后根据类型看走服务注册还是服务注销。

nacos 注册到dubbo_nacos 注册到dubbo_12


nacos 注册到dubbo_客户端_13

Service实例它重写了equase和hashcode方法,通过namespace、group、name来确定唯一实例,临时实例的注册表保存在内存中,该ConcurrentMap就是服务的注册表,以service来作为key,多个clientId来作为value,这也是为啥Service必须要重写equase和hashcode方法的原因

// 服务注册表ConcurrentMap<Service, Set<String>> publisherIndexes = new ConcurrentHashMap<>()

我们继续看下面的方法逻辑

nacos 注册到dubbo_服务端_14

该方法中主要做了以下事情:

  1. 通过ServiceManager和service获取了一个Service,实际上这里是为了确保service的单例,防止同一namespace、group、name相同的生成多个Service实例,毕竟Service实例在注册表中是以key存在的,必须唯一

nacos 注册到dubbo_客户端_15

  1. 通过clientId获取了Client对象(IpPortBasedClient),该client对象在进入InstanceRequestHandler#handle方法前就已经加入到clientManager中的,不信可以在ConnectionBasedClientManager#clientConnected方法入口处打个断点,就可以知道。
  2. 将客户端注册实例信息转换成服务端注册信息,然后将Service和注册实例信息添加到Client中,最后再更新客户端的心跳时间
  3. 发布服务注册事件ClientRegisterServiceEvent和实例元数据事件

服务注册事件处理过程中,会将服务的注册信息注册到注册中心的注册表中,也就是我们上面说的那个ConcurrentMap,我们看下该事件的监听位置和处理逻辑代码

服务注册的监听器方法为:ClientServiceIndexesManager#onEvent

nacos 注册到dubbo_服务端_16

nacos 注册到dubbo_自动装配_17

nacos 注册到dubbo_nacos 注册到dubbo_18

通过以上方法,我们知道事件处理时,将待注册服务想Nacos的注册表中进行了注册工作,然后发布了一个服务变更的事件。

服务变更事件有两个监听方法,一个是通知该服务的所有服务订阅者,还有一个就是通知集群进行数据同步

1.通知订阅者事件:

nacos 注册到dubbo_客户端_19

2.集群同步事件

nacos 注册到dubbo_自动装配_20


nacos 注册到dubbo_客户端_21

集群同步

集群同步放单独的文章去讲解。