Nacos(一)源码分析Nacos注册示例流程
nacos官方地址:https://nacos.io/zh-cn/
大家可以看一下nacos的中文手册以及官方源码,博主就不带领大家快速入门 了,官方文档中都有而且非常标准,比其他博客写的好多了并且还是实时更新的。
先看一下博主给大家画的流程图,掌握一下大概的基本流程,好理解,博主给大家讲源码:
https://www.processon.com/view/link/5f7e895be0b34d0711f65178
nacos最主要的功能就是服务注册及发现,那它到底是如何实现的呢?博主用的springboot开发的,所以直接就去找nacos的jar包下的spring.factories,这是每个要自动注入的服务jar的必备文件,我们来看一下

里面有很多的自动配置类,我们只看一下NacosServiceRegistryAutoConfiguration,该类主要做的是服务注册的相关事宜,如果大家第一次看源码的话不知道该如何下手,最笨的方法就是一个一个看。总会找到的,最好要找名字看起来就像自己找的,因为这是阿里巴巴开发的,他们是有java开发规范的,要做到见名知意。
1 /**
2 * @author xiaojing
3 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
4 */
5 @Configuration(proxyBeanMethods = false)
6 @EnableConfigurationProperties
7 @ConditionalOnNacosDiscoveryEnabled
8 @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
9 matchIfMissing = true)
10 @AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
11 AutoServiceRegistrationAutoConfiguration.class,
12 NacosDiscoveryAutoConfiguration.class })
13 public class NacosServiceRegistryAutoConfiguration {
14
15 @Bean
16 public NacosServiceRegistry nacosServiceRegistry(
17 NacosDiscoveryProperties nacosDiscoveryProperties) {
18 return new NacosServiceRegistry(nacosDiscoveryProperties);
19 }
20
21 @Bean
22 @ConditionalOnBean(AutoServiceRegistrationProperties.class)
23 public NacosRegistration nacosRegistration(
24 NacosDiscoveryProperties nacosDiscoveryProperties,
25 ApplicationContext context) {
26 return new NacosRegistration(nacosDiscoveryProperties, context);
27 }
28
29 @Bean
30 @ConditionalOnBean(AutoServiceRegistrationProperties.class)
31 public NacosAutoServiceRegistration nacosAutoServiceRegistration(
32 NacosServiceRegistry registry,
33 AutoServiceRegistrationProperties autoServiceRegistrationProperties,
34 NacosRegistration registration) {
35 //这里才是自动注入的类,我们需要进去看一下
36 return new NacosAutoServiceRegistration(registry,
37 autoServiceRegistrationProperties, registration);
38 }
39
40 }
1 public class NacosAutoServiceRegistration
2 extends AbstractAutoServiceRegistration<Registration> {
3
4 private static final Logger log = LoggerFactory
5 .getLogger(NacosAutoServiceRegistration.class);
6
7 private NacosRegistration registration;
8
9 public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,
10 AutoServiceRegistrationProperties autoServiceRegistrationProperties,
11 NacosRegistration registration) {
12 super(serviceRegistry, autoServiceRegistrationProperties);
13 this.registration = registration;
14 }
15
16 @Deprecated
17 public void setPort(int port) {
18 getPort().set(port);
19 }
20
21 @Override
22 protected NacosRegistration getRegistration() {
23 if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
24 this.registration.setPort(this.getPort().get());
25 }
26 Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
27 return this.registration;
28 }
29
30 @Override
31 protected NacosRegistration getManagementRegistration() {
32 return null;
33 }
34
35 @Override
36 protected void register() {
37 if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
38 log.debug("Registration disabled.");
39 return;
40 }
41 if (this.registration.getPort() < 0) {
42 this.registration.setPort(getPort().get());
43 }
44 super.register();
45 }
46
47 @Override
48 protected void registerManagement() {
49 if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
50 return;
51 }
52 super.registerManagement();
53
54 }
55
56 @Override
57 protected Object getConfiguration() {
58 return this.registration.getNacosDiscoveryProperties();
59 }
60
61 @Override
62 protected boolean isEnabled() {
63 return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
64 }
65
66 @Override
67 @SuppressWarnings("deprecation")
68 protected String getAppName() {
69 String appName = registration.getNacosDiscoveryProperties().getService();
70 return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
71 }
72
73 }
看到这里,大家可能有点懵,我应该找那个方法呢?大家可以看一下构造器中,引用了父类,当我们看到父类的时候,发现父类实现了ApplicationListener,这个类大家不陌生,系统会自动执行其onApplicationEvent而正好我们的类实现了这个方法,最后我们发现了应该看register() 方法,大家可以来看看这个方法的实现
1 @Override
2 public void register(Registration registration) {
3
4 if (StringUtils.isEmpty(registration.getServiceId())) {
5 log.warn("No service to register for nacos client...");
6 return;
7 }
8 //看到这两个参数,大家看过nacos文档就知道这两个参数要干啥用了
9 String serviceId = registration.getServiceId();
10 String group = nacosDiscoveryProperties.getGroup();
11 //要发送的实例对象,具体的属性,大家可以看看这个方法
12 Instance instance = getNacosInstanceFromRegistration(registration);
13
14 try {
15 //走这里,是真正的注册服务
16 namingService.registerInstance(serviceId, group, instance);
17 log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
18 instance.getIp(), instance.getPort());
19 }
20 catch (Exception e) {
21 log.error("nacos registry, {} register failed...{},", serviceId,
22 registration.toString(), e);
23 // rethrow a RuntimeException if the registration is failed.
24 // issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
25 rethrowRuntimeException(e);
26 }
27 }
1 @Override
2 public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
3 //是否是临时的,这个参数默认是临时实例,这个是临时或者是否持久很重要,先记住
4 if (instance.isEphemeral()) {
5 //填写各种心跳信息,毕竟服务需要往nacos发送心跳,nacos才能知道该服务是否还存活
6 BeatInfo beatInfo = new BeatInfo();
7 beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));
8 beatInfo.setIp(instance.getIp());
9 beatInfo.setPort(instance.getPort());
10 beatInfo.setCluster(instance.getClusterName());
11 beatInfo.setWeight(instance.getWeight());
12 beatInfo.setMetadata(instance.getMetadata());
13 beatInfo.setScheduled(false);
14 beatInfo.setPeriod(instance.getInstanceHeartBeatInterval());
15 //看一下客服端是如何发送心跳
16 beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);
17 }
18 //注册服务
19 serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);
20 }
1 @Override
2 public void run() {
3 if (beatInfo.isStopped()) {
4 return;
5 }
6 long nextTime = beatInfo.getPeriod();
7 try {
8 //会调用nacos服务端的/instance/beat接口
9 JSONObject result = serverProxy.sendBeat(beatInfo, BeatReactor.this.lightBeatEnabled);
10 long interval = result.getIntValue("clientBeatInterval");
11 boolean lightBeatEnabled = false;
12 if (result.containsKey(CommonParams.LIGHT_BEAT_ENABLED)) {
13 lightBeatEnabled = result.getBooleanValue(CommonParams.LIGHT_BEAT_ENABLED);
14 }
15 BeatReactor.this.lightBeatEnabled = lightBeatEnabled;
16 if (interval > 0) {
17 nextTime = interval;
18 }
19 int code = NamingResponseCode.OK;
20 if (result.containsKey(CommonParams.CODE)) {
21 code = result.getIntValue(CommonParams.CODE);
22 }
23 //如果找不到服务,则进行注册服务
24 if (code == NamingResponseCode.RESOURCE_NOT_FOUND) {
25 Instance instance = new Instance();
26 instance.setPort(beatInfo.getPort());
27 instance.setIp(beatInfo.getIp());
28 instance.setWeight(beatInfo.getWeight());
29 instance.setMetadata(beatInfo.getMetadata());
30 instance.setClusterName(beatInfo.getCluster());
31 instance.setServiceName(beatInfo.getServiceName());
32 instance.setInstanceId(instance.getInstanceId());
33 instance.setEphemeral(true);
34 try {
35 //该方法封装好参数后,会调用/instance接口
36 serverProxy.registerService(beatInfo.getServiceName(),
37 NamingUtils.getGroupName(beatInfo.getServiceName()), instance);
38 } catch (Exception ignore) {
39 }
40 }
41 } catch (NacosException ne) {
42 NAMING_LOGGER.error("[CLIENT-BEAT] failed to send beat: {}, code: {}, msg: {}",
43 JSON.toJSONString(beatInfo), ne.getErrCode(), ne.getErrMsg());
44
45 }
46 //定时线程池不会一直循环进行调用,所以每次执行完之后会继续添加定时任务进行发送心跳
47 executorService.schedule(new BeatTask(beatInfo), nextTime, TimeUnit.MILLISECONDS);
48 }
看完发送心跳的方法,我们该看注册服务的方法了:serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);其实就是发送心跳后,找不到服务时调用的/instance接口。
到此,我们的服务就会注册到nacos服务端中,客户端的代码就是如此,还是挺简单的,我们下一篇就会带大家走进服务端的代码。
Nacos(一)源码分析Nacos注册示例流程的更多相关文章
- Yii2 源码分析 入口文件执行流程
Yii2 源码分析 入口文件执行流程 1. 入口文件:web/index.php,第12行.(new yii\web\Application($config)->run()) 入口文件主要做4 ...
- Solr4.8.0源码分析(5)之查询流程分析总述
Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilt ...
- (转)linux内存源码分析 - 内存回收(整体流程)
http://www.cnblogs.com/tolimit/p/5435068.html------------linux内存源码分析 - 内存回收(整体流程) 概述 当linux系统内存压力就大时 ...
- HDFS源码分析DataXceiver之整体流程
在<HDFS源码分析之DataXceiverServer>一文中,我们了解到在DataNode中,有一个后台工作的线程DataXceiverServer.它被用于接收来自客户端或其他数据节 ...
- JVM源码分析之JVM启动流程
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 “365篇原创计划”第十四篇. 今天呢!灯塔君跟大家讲: JVM源码分析之JVM启动流程 前言: 执行Java类的main方法,程序就能运 ...
- Nacos(二)源码分析Nacos服务端注册示例流程
上回我们讲解了客户端配置好nacos后,是如何进行注册到服务器的,那我们今天来讲解一下服务器端接收到注册实例请求后会做怎么样的处理. 首先还是把博主画的源码分析图例发一下,让大家对整个流程有一个大概的 ...
- Java并发包中Semaphore的工作原理、源码分析及使用示例
1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后 ...
- Hadoop RCFile存储格式详解(源码分析、代码示例)
RCFile RCFile全称Record Columnar File,列式记录文件,是一种类似于SequenceFile的键值对(Key/Value Pairs)数据文件. 关键词:Reco ...
- springMVC源码分析--AbstractHandlerMethodMapping注册url和HandlerMethod对应关系(十一)
在上一篇博客springMVC源码分析--AbstractHandlerMethodMapping获取url和HandlerMethod对应关系(十)中我们简单地介绍了获取url和HandlerMet ...
- illuminate/routing 源码分析之注册路由
我们知道,在 Laravel 世界里,外界传进来一个 Request 时,会被 Kernel 处理并返回给外界一个 Response.Kernel 在处理 Request 时,会调用 illumina ...
随机推荐
- Grakn Forces 2020 ABCDE题解
看到老外评论区中说,这场的难度估计是\(div.1\)和\(div.1.5\)的合并 A. Circle Coloring #构造 题目链接 题意 给定三个长度为\(n\)数组\(a,b,c\),要你 ...
- unittest框架中读取有特殊符号的配置文件内容的方法-configparser的RawConfigParser类应用
在搭建Unittest框架中,出现了一个问题,配置文件.ini中,出现了特殊字符如何处理? 通过 1.configparser的第三方库对应的ConfigParser类,无法完成对特殊字符的读取: # ...
- 洛谷 P3410 拍照(最大流 + 建图)
这道题问的是一群人要和另一群人合影,每个客人都有必须在场的人全部在场才能在场,每个客人给的有收入,但是邀请也需要支出,问最大收入? 我觉得可以总结为一类问题,就是有先决条件的网络流问题.看到费用和支出 ...
- 第7.12节 可共享的Python类变量
第7.12节 可共享的Python类变量 一. 引言 在上节已经引入介绍了类变量和实例变量,类体中定义的变量为类变量,默认属于类本身,实例变量是实例方法中定义的self对象的变量,对于每个实例都 ...
- PyQt(Python+Qt)学习随笔:Qt Designer中主窗口对象unifiedTitleAndToolBarOnMac属性
unifiedTitleAndToolBarOnMac 用于确认在mac操作系统上是否使用统一的标题和工具栏外观 有如下几个限制: 1.不支持使用带OpenGl内容的窗口,包括QGLWidget 和 ...
- python序列化与反序列化(json、pickle)-(五)
1.什么是序列化&反序列化? 序列化:将字典.列表.类的实例对象等内容转换成一个字符串的过程. 反序列化:将一个字符串转换成字典.列表.类的实例对象等内容的过程 PS:Python中常见的数据 ...
- Xmind Invalid Configuarton Location(the configuarton area is not writable)
今天在安装Xmind的时候,发现如下错误,原因:配置问题 步骤如下: 1.找到XMind安装目录下的文件XMind.ini2.文件中的内容替换:将:-configuration./configurat ...
- 【SDOI2017】天才黑客(前后缀优化建图 & 最短路)
Description 给定一张有向图,\(n\) 个点,\(m\) 条边.第 \(i\) 条边上有一个边权 \(c_i\),以及一个字符串 \(s_i\). 其中字符串 \(s_1, s_2, \c ...
- Java并发编程的艺术(二)——volatile、原子性
什么是volatile Java语言允许线程访问共享变量,为了确保共享变量能够被准确一致地更新,如果一个字段被声明为volatile,那么Java内存模型将会确保所有线程看到这个变量时值是一致的.保证 ...
- x64架构下Linux系统函数调用
原文链接:https://blog.fanscore.cn/p/27/ 一. 函数调用相关指令 关于栈可以看下我之前的这篇文章x86 CPU与IA-32架构 在开始函数调用约定之前我们需要先了解一下几 ...