一.初始化
NamingService naming = NamingFactory.createNamingService(properties);
二.通过反射传入properties生成NacosNamingService的实例
/**
* Create a new naming service.
*
* @param properties naming service properties
* @return new naming service
* @throws NacosException nacos exception
*/
public static NamingService createNamingService(Properties properties) throws NacosException {
try {
Class<?> driverImplClass = Class.forName("com.alibaba.nacos.client.naming.NacosNamingService");
Constructor constructor = driverImplClass.getConstructor(Properties.class);
NamingService vendorImpl = (NamingService) constructor.newInstance(properties);
return vendorImpl;
} catch (Throwable e) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, e);
}
}
三.init初始化

 public NacosNamingService(Properties properties) throws NacosException {
init(properties);
} private void init(Properties properties) throws NacosException {
ValidatorUtils.checkInitParam(properties);
this.namespace = InitUtils.initNamespaceForNaming(properties);
InitUtils.initSerialization();
//解析serverlist,endpoint
initServerAddr(properties);
InitUtils.initWebRootContext();
//缓存地址C:\Users\admin\nacos\naming\fe3078a2-019d-4fdd-b6cf-22c3117f847d
initCacheDir();
//初始化日志信息
initLogName(properties);
//监听事件变更
this.eventDispatcher = new EventDispatcher();
//1.根据endpoint查找serverlist,nacos服务器地址;2.安全登陆验证
this.serverProxy = new NamingProxy(this.namespace, this.endpoint, this.serverList, properties);
//与服务端建立上报机制
this.beatReactor = new BeatReactor(this.serverProxy, initClientBeatThreadCount(properties));
this.hostReactor = new HostReactor(this.eventDispatcher, this.serverProxy, beatReactor, this.cacheDir,
isLoadCacheAtStart(properties), initPollingThreadCount(properties));
}
 
四.EventDispatcher 监听事件分发
public EventDispatcher() {

        this.executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "com.alibaba.nacos.naming.client.listener");
thread.setDaemon(true); return thread;
}
}); this.executor.execute(new Notifier());
}

//changedServices 改变的服务
private final BlockingQueue<ServiceInfo> changedServices = new LinkedBlockingQueue<ServiceInfo>();
//服务 - 监听器回调
private final ConcurrentMap<String, List<EventListener>> observerMap = new ConcurrentHashMap<String, List<EventListener>>();
private class Notifier implements Runnable { @Override
public void run() {
while (!closed) { ServiceInfo serviceInfo = null;
try {
serviceInfo = changedServices.poll(5, TimeUnit.MINUTES);
} catch (Exception ignore) {
} if (serviceInfo == null) {
continue;
} try {
List<EventListener> listeners = observerMap.get(serviceInfo.getKey()); if (!CollectionUtils.isEmpty(listeners)) {
for (EventListener listener : listeners) {
List<Instance> hosts = Collections.unmodifiableList(serviceInfo.getHosts());
listener.onEvent(new NamingEvent(serviceInfo.getName(), serviceInfo.getGroupName(),
serviceInfo.getClusters(), hosts));
}
} } catch (Exception e) {
NAMING_LOGGER.error("[NA] notify error for service: " + serviceInfo.getName() + ", clusters: "
+ serviceInfo.getClusters(), e);
}
}
}
}
五.NamingProxy
1.根据endpoint查找serverlist,nacos服务器地址;2.安全登陆验证
public NamingProxy(String namespaceId, String endpoint, String serverList, Properties properties) {

        this.securityProxy = new SecurityProxy(properties, nacosRestTemplate);
this.properties = properties;
this.setServerPort(DEFAULT_SERVER_PORT);
this.namespaceId = namespaceId;
this.endpoint = endpoint;
if (StringUtils.isNotEmpty(serverList)) {
this.serverList = Arrays.asList(serverList.split(","));
if (this.serverList.size() == 1) {
this.nacosDomain = serverList;
}
}
this.initRefreshTask();
}
private void initRefreshTask() {

        this.executorService = new ScheduledThreadPoolExecutor(2, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.client.naming.updater");
t.setDaemon(true);
return t;
}
}); this.executorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
//根据endpoint定时刷新serverlist地址
refreshSrvIfNeed();
}
}, 0, vipSrvRefInterMillis, TimeUnit.MILLISECONDS); this.executorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
//定时安全登陆验证
securityProxy.login(getServerList());
}
}, 0, securityInfoRefreshIntervalMills, TimeUnit.MILLISECONDS); refreshSrvIfNeed();
this.securityProxy.login(getServerList());
}
六.初始化心跳线程池
 public BeatReactor(NamingProxy serverProxy, int threadCount) {
this.serverProxy = serverProxy;
this.executorService = new ScheduledThreadPoolExecutor(threadCount, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.naming.beat.sender");
return thread;
}
});
}
 
七.HostReactor
ublic HostReactor(EventDispatcher eventDispatcher, NamingProxy serverProxy, BeatReactor beatReactor,
String cacheDir, boolean loadCacheAtStart, int pollingThreadCount) {
// init executorService
this.executor = new ScheduledThreadPoolExecutor(pollingThreadCount, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.client.naming.updater");
return thread;
}
});
this.eventDispatcher = eventDispatcher;
this.beatReactor = beatReactor;
this.serverProxy = serverProxy;
this.cacheDir = cacheDir;
if (loadCacheAtStart) {
this.serviceInfoMap = new ConcurrentHashMap<String, ServiceInfo>(DiskCache.read(this.cacheDir));
} else {
this.serviceInfoMap = new ConcurrentHashMap<String, ServiceInfo>(16);
} this.updatingMap = new ConcurrentHashMap<String, Object>();
//容灾备份策略
this.failoverReactor = new FailoverReactor(this, cacheDir);
//接收服务器端的数据
this.pushReceiver = new PushReceiver(this);
}
 
 
八.PushReceiver
public PushReceiver(HostReactor hostReactor) {
try {
this.hostReactor = hostReactor;
this.udpSocket = new DatagramSocket();
this.executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("com.alibaba.nacos.naming.push.receiver");
return thread;
}
}); this.executorService.execute(this);
} catch (Exception e) {
NAMING_LOGGER.error("[NA] init udp socket failed", e);
}
}
九.run 方法
@Override
public void run() {
while (!closed) {
try { // byte[] is initialized with 0 full filled by default
byte[] buffer = new byte[UDP_MSS];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length); udpSocket.receive(packet); String json = new String(IoUtils.tryDecompress(packet.getData()), UTF_8).trim();
NAMING_LOGGER.info("received push data: " + json + " from " + packet.getAddress().toString()); PushPacket pushPacket = JacksonUtils.toObj(json, PushPacket.class);
String ack;
if ("dom".equals(pushPacket.type) || "service".equals(pushPacket.type)) {
//处理从服务端接收的数据
hostReactor.processServiceJson(pushPacket.data); // send ack to server
ack = "{\"type\": \"push-ack\"" + ", \"lastRefTime\":\"" + pushPacket.lastRefTime + "\", \"data\":"
+ "\"\"}";
} else if ("dump".equals(pushPacket.type)) {
// dump data to server
ack = "{\"type\": \"dump-ack\"" + ", \"lastRefTime\": \"" + pushPacket.lastRefTime + "\", \"data\":"
+ "\"" + StringUtils.escapeJavaScript(JacksonUtils.toJson(hostReactor.getServiceInfoMap()))
+ "\"}";
} else {
// do nothing send ack only
ack = "{\"type\": \"unknown-ack\"" + ", \"lastRefTime\":\"" + pushPacket.lastRefTime
+ "\", \"data\":" + "\"\"}";
}
//发送ack给服务器端
udpSocket.send(new DatagramPacket(ack.getBytes(UTF_8), ack.getBytes(UTF_8).length,
packet.getSocketAddress()));
} catch (Exception e) {
if (closed) {
return;
}
NAMING_LOGGER.error("[NA] error while receiving push data", e);
}
}
}
 
十.处理服务器端数据
public ServiceInfo processServiceJson(String json) {
ServiceInfo serviceInfo = JacksonUtils.toObj(json, ServiceInfo.class);
ServiceInfo oldService = serviceInfoMap.get(serviceInfo.getKey());
if (serviceInfo.getHosts() == null || !serviceInfo.validate()) {
//empty or error push, just ignore
return oldService;
} boolean changed = false; if (oldService != null) {
//处理服务器端数据,判断是新增,删除,还是修改
if (oldService.getLastRefTime() > serviceInfo.getLastRefTime()) {
NAMING_LOGGER.warn("out of date data received, old-t: " + oldService.getLastRefTime() + ", new-t: "
+ serviceInfo.getLastRefTime());
}
//向服务缓存map中,放置新的服务
serviceInfoMap.put(serviceInfo.getKey(), serviceInfo); Map<String, Instance> oldHostMap = new HashMap<String, Instance>(oldService.getHosts().size());
for (Instance host : oldService.getHosts()) {
oldHostMap.put(host.toInetAddr(), host);
} Map<String, Instance> newHostMap = new HashMap<String, Instance>(serviceInfo.getHosts().size());
for (Instance host : serviceInfo.getHosts()) {
newHostMap.put(host.toInetAddr(), host);
} Set<Instance> modHosts = new HashSet<Instance>();
Set<Instance> newHosts = new HashSet<Instance>();
Set<Instance> remvHosts = new HashSet<Instance>(); List<Map.Entry<String, Instance>> newServiceHosts = new ArrayList<Map.Entry<String, Instance>>(
newHostMap.entrySet());
for (Map.Entry<String, Instance> entry : newServiceHosts) {
Instance host = entry.getValue();
String key = entry.getKey();
if (oldHostMap.containsKey(key) && !StringUtils
.equals(host.toString(), oldHostMap.get(key).toString())) {
modHosts.add(host);
continue;
} if (!oldHostMap.containsKey(key)) {
newHosts.add(host);
}
} for (Map.Entry<String, Instance> entry : oldHostMap.entrySet()) {
Instance host = entry.getValue();
String key = entry.getKey();
if (newHostMap.containsKey(key)) {
continue;
} if (!newHostMap.containsKey(key)) {
remvHosts.add(host);
} } if (newHosts.size() > 0) {
changed = true;
NAMING_LOGGER.info("new ips(" + newHosts.size() + ") service: " + serviceInfo.getKey() + " -> "
+ JacksonUtils.toJson(newHosts));
} if (remvHosts.size() > 0) {
changed = true;
NAMING_LOGGER.info("removed ips(" + remvHosts.size() + ") service: " + serviceInfo.getKey() + " -> "
+ JacksonUtils.toJson(remvHosts));
} if (modHosts.size() > 0) {
changed = true;
updateBeatInfo(modHosts);
NAMING_LOGGER.info("modified ips(" + modHosts.size() + ") service: " + serviceInfo.getKey() + " -> "
+ JacksonUtils.toJson(modHosts));
} serviceInfo.setJsonFromServer(json); if (newHosts.size() > 0 || remvHosts.size() > 0 || modHosts.size() > 0) {
//向事件缓存list changedServices中写入变更事件
eventDispatcher.serviceChanged(serviceInfo);
//写入缓存
DiskCache.write(serviceInfo, cacheDir);
} } else {
changed = true;
NAMING_LOGGER.info("init new ips(" + serviceInfo.ipCount() + ") service: " + serviceInfo.getKey() + " -> "
+ JacksonUtils.toJson(serviceInfo.getHosts()));
serviceInfoMap.put(serviceInfo.getKey(), serviceInfo);
eventDispatcher.serviceChanged(serviceInfo);
serviceInfo.setJsonFromServer(json);
DiskCache.write(serviceInfo, cacheDir);
} MetricsMonitor.getServiceInfoMapSizeMonitor().set(serviceInfoMap.size()); if (changed) {
NAMING_LOGGER.info("current ips:(" + serviceInfo.ipCount() + ") service: " + serviceInfo.getKey() + " -> "
+ JacksonUtils.toJson(serviceInfo.getHosts()));
} return serviceInfo;
}
nacos配置加刷新流程图
 

Nacos源码深度解析1-服务注册初始化(客户端)的更多相关文章

  1. mybatis 3.x源码深度解析与最佳实践(最完整原创)

    mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...

  2. spring源码深度解析— IOC 之 容器的基本实现

    概述 上一篇我们搭建完Spring源码阅读环境,spring源码深度解析—Spring的整体架构和环境搭建 这篇我们开始真正的阅读Spring的源码,分析spring的源码之前我们先来简单回顾下spr ...

  3. spring源码深度解析— IOC 之 默认标签解析(上)

    概述 接前两篇文章  spring源码深度解析—Spring的整体架构和环境搭建  和  spring源码深度解析— IOC 之 容器的基本实现 本文主要研究Spring标签的解析,Spring的标签 ...

  4. spring源码深度解析— IOC 之 开启 bean 的加载

    概述 前面我们已经分析了spring对于xml配置文件的解析,将分析的信息组装成 BeanDefinition,并将其保存注册到相应的 BeanDefinitionRegistry 中.至此,Spri ...

  5. spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理

    @Configuration注解提供了全新的bean创建方式.最初spring通过xml配置文件初始化bean并完成依赖注入工作.从spring3.0开始,在spring framework模块中提供 ...

  6. Go netpoll I/O 多路复用构建原生网络模型之源码深度解析

    导言 Go 基于 I/O multiplexing 和 goroutine 构建了一个简洁而高性能的原生网络模型(基于 Go 的I/O 多路复用 netpoll),提供了 goroutine-per- ...

  7. Spring源码深度解析之Spring MVC

    Spring源码深度解析之Spring MVC Spring框架提供了构建Web应用程序的全功能MVC模块.通过策略接口,Spring框架是高度可配置的,而且支持多种视图技术,例如JavaServer ...

  8. SpringMVC 源码深度解析&lt;context:component-scan&gt;(扫描和注冊的注解Bean)

    我们在SpringMVC开发项目中,有的用注解和XML配置Bean,这两种都各有自己的优势,数据源配置比較经经常使用XML配置.控制层依赖的service比較经经常使用注解等(在部署时比較不会改变的) ...

  9. 并发编程(十五)——定时器 ScheduledThreadPoolExecutor 实现原理与源码深度解析

    在上一篇线程池的文章<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中从ThreadPoolExecutor源码分析了其运行机制.限于篇幅,留下了Scheduled ...

随机推荐

  1. FTP的PORT(主动模式)和PASV(被动模式)

    最近做一个项目用到FTP和其它系统进行文件传输,结果在FTP网络连接的问题上花了很多时间,由于太久没搞多FTP,忘记了FTP不单单开放21端口,客户端采用不同连接模式对网络有不同.在此重温一下FTP的 ...

  2. springboot实战开发全套教程,让开发像搭积木一样简单!Github星标已上10W+!

    前言 先说一下,这份教程在github上面星标已上10W,下面我会一一给大家举例出来全部内容,原链接后面我会发出来!首先我讲一下接下来我们会讲到的知识和技术,对比讲解了多种同类技术的使用手日区别,大家 ...

  3. 使用CorelDRAW修饰用于打印的图像

    CorelDRAW在打印输出方面一直做的非常棒,它不仅是一款专业的矢量绘图软件,位图处理也是很厉害的.本文我们讲述修饰.处理数码相机图像,以便将其用于 CMYK 打印作业的一些重要步骤,先来看下被调整 ...

  4. 数据丢失如何恢复?EasyRecovery帮你快速实现

    在日常使用电脑时,我们经常会遇到误删文件的情况,若文件还未被彻底删除,我们还可以通过电脑中的回收站将其恢复,但若是回收站都被清空的话,想要恢复文件就变得比较困难了,而EasyRecovery可以很好的 ...

  5. Boom 3D快捷方式,让3D音效应用更便捷

    快捷方式是一种快速启动程序.打开程序功能的方法,巧妙地利用快捷键,可以大大加快我们使用Boom 3D的速度,可以让我们更好地享受3D音效. 接下来,就让小编演示一下怎么在不打开Boom 3D的情况下使 ...

  6. 设置searchDisplayController的searchResultsTableView的UITableViewStyle为grouped

    [self.searchDisplayController setValue:[NSNumber numberWithInt:UITableViewStyleGrouped] forKey:@&quo ...

  7. 解决Maven项目中pom.xml文件报错(Failure to transfer....)的问题

    打开pom.xml文件,查看错误,如果错误类型为:Failure to transfer.........之类的,则表明你的pom中依赖的jar包没有完全下载. 解决方法:找到你本地的maven仓库, ...

  8. pytest参数化

    Pytest可以在多个级别上实现测试参数化 一.@pytest.fixture装饰器调用参数 示例 import pytest from selenium import webdriver from ...

  9. Linux没有netstat和ifconfig命令问题

    安装了精简版命令行centos7系统,运行netsta查看端口和ifconfig查看IP命令都提示找不到命令. 解决方法: yum search ifconfig 通过yum search 这个命令我 ...

  10. VMware与Device/Credential Guard不兼容问题

    启动虚拟机vmware突然报不兼容错误 解决方法: 1首先打开控制面板>程序>启动或关闭Windows功能, 取消Hyper-v的勾选 2.在往下划,关闭Windows沙盒的勾选沙盒和虚拟 ...