前面一篇文章讲了客户端启动时候会去调用nacos服务端发起http请求进行服务注册,最终会调用到
/nacos/v1/ns/instance这个接口上面,今天我们重点 来看服务是如何完成服务注册的,首先我们将nacos的源码下载下载,这里我下载的是1.4.1版本,根据接口路径找到nacos服务端注册源码入口
![](https://i-blog.csdnimg.cn/blog_migrate/5ab90e77893424579f534f7e697772a3.png)
这个接口会调用serviceManager.registerInstance(namespaceId, serviceName, instance);这个方法
![](https://i-blog.csdnimg.cn/blog_migrate/798478c9bd2176bdb5857adea1bc11d5.png)
这里有两个重要的方法,一个是如果当前服务在nacos注册中心没有,会创建一个初始化的数据结构,这个后面在相信讲解,我们重点关注addInstance(namespaceId, serviceName, instance.isEphemeral(), instance)这个方法
![](https://i-blog.csdnimg.cn/blog_migrate/2cccf94868da916caa10c5f1c1d342fd.png)
这里会调用ConsistencyService这个类的put方法
![](https://i-blog.csdnimg.cn/blog_migrate/4a293700bb5a1809e9ef6749cfca24bf.png)
这里注入的是名称叫consistencyDelegate这个bean,最终会调用这个DelegateConsistencyServiceImpl这个实现类的put方法
![](https://i-blog.csdnimg.cn/blog_migrate/27cc65a175b2c42a8fcd6141145dd162.png)
![](https://i-blog.csdnimg.cn/blog_migrate/593c6644dff9468bc2fb853d392b08dc.png)
根据传入的是临时实例还是持久实例,返回不同的策略类,默认是临时实例,所以会调用到DistroConsistencyServiceImpl这个类的put方法
![](https://i-blog.csdnimg.cn/blog_migrate/a0c6bcb286162831760b37ffed3f31eb.png)
然后会调用onPut方法
![](https://i-blog.csdnimg.cn/blog_migrate/fbe8efa77fdd60bc57c34613a6b70e55.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c94153c4dd53ae7c575b66acef25b78d.png)
最终这里会将服务数据封装成一个Pair对象放到一个阻塞队列里面,这里这种注册异步化的思想,值得我们学习借鉴,这样能够大大提升性能,这里将注册实例任务放到了阻塞队列里面,肯定有一个地方有消费者从队列里面拿任务进行处理,在DistroConsistencyServiceImpl这个类里面有一个init方法
![](https://i-blog.csdnimg.cn/blog_migrate/1ae60570977818ddf1950844094eff3f.png)
这个方法被标注的PostConstruct注解,熟悉spring源码的,这个方法会在这个bean初始化后进行回调用
![](https://i-blog.csdnimg.cn/blog_migrate/05f694c3d5d90decec9c708637b84028.png)
这个方法最终会调用线程池执行,线程池提交的任务是这个Notifier的类,我们跟进去不难发现这个是一个实现了Runnable的类,最终会调用到这个类的run方法
![](https://i-blog.csdnimg.cn/blog_migrate/1ab6cd652b98105f85965e80584bd27f.png)
这里面使用了自旋,然后不断从阻塞队列里面拿任务进行处理,
![](https://i-blog.csdnimg.cn/blog_migrate/32249740b487a26a7f241364316e7f37.png)
因为我们传过来的事件是change事件,最终会调用listener.onChange(datumKey, dataStore.get(datumKey).value)这个方法。这里会调用到Service类里面的onChange方法
![](https://i-blog.csdnimg.cn/blog_migrate/e956a1c21ce108699522103c7ca352da.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c180a29afa62046e48bed7a9d4524973.png)
继续跟这个方法
![](https://i-blog.csdnimg.cn/blog_migrate/ba4950a99b885a76509550026cd46dbf.png)
这里面更新注册表内存方法里,为了防止读写并发冲突,运用了CopyOnWrite写时复制的思想,具体的做法就是把原内存结构复制一份,操作完成以后再替换回真正的注册表内存,这里和Eureka的做法不太一样,Eureka采用的是多层级缓存架构,后台用线程定时同步数据,客户端感知就不让nacos这么及时
![](https://i-blog.csdnimg.cn/blog_migrate/ae7c795bd11a0590328cbe766d457dc8.png)
操作完成以后最终将Cluser这个类里面的实例成员变量替换,这里就完成的实例的注册整个流程