spring cloud alibaba 学习(三)Nacos-NacosNamingService初始化流程

2023-11-16


1、NacosServiceManager 的创建

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosServiceAutoConfiguration {

	@Bean
	public NacosServiceManager nacosServiceManager() {
		return new NacosServiceManager();
	}

}

2、NacosWatch 的创建

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnBlockingDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class,
		CommonsClientAutoConfiguration.class })
@AutoConfigureAfter(NacosDiscoveryAutoConfiguration.class)
public class NacosDiscoveryClientConfiguration {

	@Bean
	public DiscoveryClient nacosDiscoveryClient(
			NacosServiceDiscovery nacosServiceDiscovery) {
		return new NacosDiscoveryClient(nacosServiceDiscovery);
	}

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnProperty(value = "spring.cloud.nacos.discovery.watch.enabled",
			matchIfMissing = true)
	public NacosWatch nacosWatch(NacosServiceManager nacosServiceManager,
			NacosDiscoveryProperties nacosDiscoveryProperties,
			ObjectProvider<ThreadPoolTaskScheduler> taskExecutorObjectProvider) {
		return new NacosWatch(nacosServiceManager, nacosDiscoveryProperties,
				taskExecutorObjectProvider);
	}

}

3、在NacosWatch 的 start 方法中会通过nacosServiceManager创建 NacosNamingService

NamingService namingService = nacosServiceManager
					.getNamingService(properties.getNacosProperties());
public NamingService getNamingService(Properties properties) {
		if (Objects.isNull(this.namingService)) {
			//构建 NamingService 
			buildNamingService(properties);
		}
		return namingService;
	}

4、buildNamingService( )

private NamingService buildNamingService(Properties properties) {
		if (Objects.isNull(namingService)) {
			synchronized (NacosServiceManager.class) {
				if (Objects.isNull(namingService)) {
					namingService = createNewNamingService(properties);
				}
			}
		}
		return namingService;
	}

5、createNewNamingService( )

private NamingService createNewNamingService(Properties properties) {
		try {
			return createNamingService(properties);
		}
		catch (NacosException e) {
			throw new RuntimeException(e);
		}
	}
 public static NamingService createNamingService(Properties properties) throws NacosException {
        return NamingFactory.createNamingService(properties);
    }
 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);
        }
    }

可以看出,这里是通过反射的方式调用 com.alibaba.nacos.client.naming.NacosNamingService 的构造方法

5、NacosNamingService 的构造方法

public NacosNamingService(Properties properties) throws NacosException {
        init(properties);
    }

6、init( )

private void init(Properties properties) throws NacosException {
        ValidatorUtils.checkInitParam(properties);
         // 初始化命名空间
        this.namespace = InitUtils.initNamespaceForNaming(properties);
        InitUtils.initSerialization();
        // 初始化Nacos注册中心服务地址
        initServerAddr(properties);
        // 初始化web上下文
        InitUtils.initWebRootContext(properties);
        // 初始化缓存目录
        initCacheDir();
        // 初始化日志文件
        initLogName(properties);
        
        //服务端的代理,用于客户端与服务端之间的通信
        this.serverProxy = new NamingProxy(this.namespace, this.endpoint, this.serverList, properties);
        //用于客户端与服务器之间的心跳通信
        this.beatReactor = new BeatReactor(this.serverProxy, initClientBeatThreadCount(properties));
        //用于客户端服务的订阅,从服务端更新服务信息
        this.hostReactor = new HostReactor(this.serverProxy, beatReactor, this.cacheDir, isLoadCacheAtStart(properties),
                isPushEmptyProtect(properties), initPollingThreadCount(properties));
    }

7、initNamespaceForNaming( )

public static String initNamespaceForNaming(Properties properties) {
        String tmpNamespace = null;
        
        //获取环境变量 isUseCloudNamespaceParsing 或 nacos.use.cloud.namespace.parsing 或 默认值true
        String isUseCloudNamespaceParsing = properties.getProperty(PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
                System.getProperty(SystemPropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING,
                        String.valueOf(Constants.DEFAULT_USE_CLOUD_NAMESPACE_PARSING)));
        
        if (Boolean.parseBoolean(isUseCloudNamespaceParsing)) {
            
            tmpNamespace = TenantUtil.getUserTenantForAns();
            tmpNamespace = TemplateUtils.stringEmptyAndThenExecute(tmpNamespace, new Callable<String>() {
                @Override
                public String call() {
                	//获取环境变量 ans.namespace
                    String namespace = System.getProperty(SystemPropertyKeyConst.ANS_NAMESPACE);
                    LogUtils.NAMING_LOGGER.info("initializer namespace from System Property :" + namespace);
                    return namespace;
                }
            });
            
            tmpNamespace = TemplateUtils.stringEmptyAndThenExecute(tmpNamespace, new Callable<String>() {
                @Override
                public String call() {
                	//获取环境变量 ALIBABA_ALIWARE_NAMESPACE
                    String namespace = System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_NAMESPACE);
                    LogUtils.NAMING_LOGGER.info("initializer namespace from System Environment :" + namespace);
                    return namespace;
                }
            });
        }
        
        tmpNamespace = TemplateUtils.stringEmptyAndThenExecute(tmpNamespace, new Callable<String>() {
            @Override
            public String call() {
            	//获取环境变量 namespace
                String namespace = System.getProperty(PropertyKeyConst.NAMESPACE);
                LogUtils.NAMING_LOGGER.info("initializer namespace from System Property :" + namespace);
                return namespace;
            }
        });
        
        if (StringUtils.isEmpty(tmpNamespace) && properties != null) {
            tmpNamespace = properties.getProperty(PropertyKeyConst.NAMESPACE);
        }
        
        tmpNamespace = TemplateUtils.stringEmptyAndThenExecute(tmpNamespace, new Callable<String>() {
            @Override
            public String call() {
            	//获取默认值 public
                return UtilAndComs.DEFAULT_NAMESPACE_ID;
            }
        });
        return tmpNamespace;
    }

8、initServerAddr( )

private void initServerAddr(Properties properties) {
        serverList = properties.getProperty(PropertyKeyConst.SERVER_ADDR);
        endpoint = InitUtils.initEndpoint(properties);
        //endpoint存在时,serverList 设置为空
        if (StringUtils.isNotEmpty(endpoint)) {
            serverList = "";
        }
    }
public static String initEndpoint(final Properties properties) {
        if (properties == null) {
            
            return "";
        }
        // Whether to enable domain name resolution rules
        //获取环境变量 isUseEndpointParsingRule 或 nacos.use.endpoint.parsing.rule 或 默认值true
        String isUseEndpointRuleParsing = properties.getProperty(PropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE,
                System.getProperty(SystemPropertyKeyConst.IS_USE_ENDPOINT_PARSING_RULE,
                        String.valueOf(ParamUtil.USE_ENDPOINT_PARSING_RULE_DEFAULT_VALUE)));
        
        boolean isUseEndpointParsingRule = Boolean.parseBoolean(isUseEndpointRuleParsing);
        String endpointUrl;
        if (isUseEndpointParsingRule) {
            // Get the set domain name information
            //获取配置 endpoint
            endpointUrl = ParamUtil.parsingEndpointRule(properties.getProperty(PropertyKeyConst.ENDPOINT));
            if (StringUtils.isBlank(endpointUrl)) {
                return "";
            }
        } else {
            endpointUrl = properties.getProperty(PropertyKeyConst.ENDPOINT);
        }
        
        if (StringUtils.isBlank(endpointUrl)) {
            return "";
        }
        
        //获取 ALIBABA_ALIWARE_ENDPOINT_PORT 或 endpointPort 或默认值8080
        String endpointPort = TemplateUtils
                .stringEmptyAndThenExecute(System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_ENDPOINT_PORT),
                        new Callable<String>() {
                            @Override
                            public String call() {
                                
                                return properties.getProperty(PropertyKeyConst.ENDPOINT_PORT);
                            }
                        });
        
        endpointPort = TemplateUtils.stringEmptyAndThenExecute(endpointPort, new Callable<String>() {
            @Override
            public String call() {
                return "8080";
            }
        });
        
        return endpointUrl + ":" + endpointPort;
    }

9、initWebRootContext( )

初始化 nacos服务端访问路径信息

public static void initWebRootContext(Properties properties) {
        final String webContext = properties.getProperty(PropertyKeyConst.CONTEXT_PATH);
        TemplateUtils.stringNotEmptyAndThenExecute(webContext, new Runnable() {
            @Override
            public void run() {
                UtilAndComs.webContext = ContextPathUtil.normalizeContextPath(webContext);
                UtilAndComs.nacosUrlBase = UtilAndComs.webContext + "/v1/ns";
                UtilAndComs.nacosUrlInstance = UtilAndComs.nacosUrlBase + "/instance";
            }
        });
        initWebRootContext();
    }
    
    /**
     * Init web root context.
     */
    @Deprecated
    public static void initWebRootContext() {
        // support the web context with ali-yun if the app deploy by EDAS
        final String webContext = System.getProperty(SystemPropertyKeyConst.NAMING_WEB_CONTEXT);
        TemplateUtils.stringNotEmptyAndThenExecute(webContext, new Runnable() {
            @Override
            public void run() {
                UtilAndComs.webContext = ContextPathUtil.normalizeContextPath(webContext);
                UtilAndComs.nacosUrlBase = UtilAndComs.webContext + "/v1/ns";
                UtilAndComs.nacosUrlInstance = UtilAndComs.nacosUrlBase + "/instance";
            }
        });
    }

10、NamingProxy

(1)构造方法

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;
        //重试次数
        this.maxRetry = ConvertUtils.toInt(properties.getProperty(PropertyKeyConst.NAMING_REQUEST_DOMAIN_RETRY_COUNT,
                String.valueOf(UtilAndComs.REQUEST_DOMAIN_RETRY_COUNT)));
        
        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;
            }
        });
        
        //定时任务 refreshSrvIfNeed
        this.executorService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                refreshSrvIfNeed();
            }
        }, 0, vipSrvRefInterMillis, TimeUnit.MILLISECONDS);
        
         //定时任务 login
        this.executorService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                securityProxy.login(getServerList());
            }
        }, 0, securityInfoRefreshIntervalMills, TimeUnit.MILLISECONDS);
        
        refreshSrvIfNeed();
        this.securityProxy.login(getServerList());
    }

(2)refreshSrvIfNeed( )

private void refreshSrvIfNeed() {
        try {
            
            //校验服务端列表serverList是否为空
            if (!CollectionUtils.isEmpty(serverList)) {
                NAMING_LOGGER.debug("server list provided by user: " + serverList);
                return;
            }
            
            //校验刷新时间间隔
            if (System.currentTimeMillis() - lastSrvRefTime < vipSrvRefInterMillis) {
                return;
            }
            
            //调用远程接口获取服务端列表 "http://" + endpoint + "/nacos/serverlist"
            List<String> list = getServerListFromEndpoint();
            
            if (CollectionUtils.isEmpty(list)) {
                throw new Exception("Can not acquire Nacos list");
            }
            
            if (!CollectionUtils.isEqualCollection(list, serversFromEndpoint)) {
                NAMING_LOGGER.info("[SERVER-LIST] server list is updated: " + list);
            }
            
            //更新服务列表serversFromEndpoint 
            serversFromEndpoint = list;
            //更新最新刷新时间
            lastSrvRefTime = System.currentTimeMillis();
        } catch (Throwable e) {
            NAMING_LOGGER.warn("failed to update server list", e);
        }
    }

(3)login( )

public boolean login(List<String> servers) {
        
        try {
        	//校验刷新时间间隔
            if ((System.currentTimeMillis() - lastRefreshTime) < TimeUnit.SECONDS
                    .toMillis(tokenTtl - tokenRefreshWindow)) {
                return true;
            }
            
            //尝试登录nacos服务列表
            for (String server : servers) {
                if (login(server)) {
                    lastRefreshTime = System.currentTimeMillis();
                    return true;
                }
            }
        } catch (Throwable ignore) {
        }
        
        return false;
    }

11、BeatReactor

客户端需要通过BeatReactor周期性的进行服务的上报,以便让nacos服务端能够实时感知服务的状态。如果一段时间内未进行上报,nacos服务端会移除该服务的注册。

12、HostReactor

HostReactor把服务信息维护到serviceInfoMap中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring cloud alibaba 学习(三)Nacos-NacosNamingService初始化流程 的相关文章

  • 【华为OD机试真题2023 JS】取出尽量少的球

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 取出尽量少的球 时间限制 1s 空间限制 32MB 限定语言 不限 题目描述 某部门开展Family Day开放日活动 其中有个从桶里取球的游戏 游戏规则如下 有N个容量一样的小
  • 使用truss、strace或ltrace诊断软件的"疑难杂症"

    作者 李凯斌 2005 01 18 11 03 24 来自 IBM DW中国 进程无法启动 软件运行速度突然变慢 程序的 Segment Fault 等等都是让每个Unix系统用户头痛的问题 本文通过三个实际案例演示如何使用truss st
  • 安卓大作业 图书管理APP

    系列文章 安卓大作业 图书管理APP 文章目录 系列文章 1 背景 2 功能 3 源代码获取 1 背景 本次实验设计的是一个图书管理系统 系统的整体目录如下 2 功能 针对于每个java类或者Activity进行说明 1 Book java
  • 最坏的时刻已经过去,静待重新走向繁荣

    今年三 四 五 六 七月份 每周客户拜访数量一直比较低 期间和客户 友商 用户持续交流 大家普遍感受到今年特别难 难于上青天 可是 我和老家做小老板亲戚朋友沟通 他们的感受没那么明显 只是觉得今年比往年差些 没一二线城市感受那么明显 进入八

随机推荐

  • Cloud Native和微服务

    一 Cloud Native介绍 Cloud Native是Matt Stine提出的一个概念 它是一个思想的集合 包括DevOps 持续交付 Continuous Delivery 微服务 MicroServices 敏捷基础设施 Agi
  • linux实例显示blocked,(11)ceph 告警:1 slow ops, oldest one blocked for

    1 ceph告警提示 1 slow ops oldest one blocked for email protected ceph s cluster id 58a12719 a5ed 4f95 b312 6efd6e34e558 heal
  • Ubuntu与Windows系统之间进行远程访问和文件的传输

    Ubuntu16 04系统之间和ubuntu与Windows10之间进行SSH远程访问和文件互传 一 Ubuntu 系统之间进行文件互传 传输的是文件夹 传输的是文件 二 ubuntu与Windows10之间进行SSH远程访问和文件互传 补
  • bugku 文件包含2

    页面很正常 url里面有一个file参数 看一下源码 有一个upload php看一下 文件上传 题目是文件包含 就想到了前面做的的上传图片马 用文件包含连接 试一试 不知到哪里出问题了 看一下上传的内容
  • python 美国总统身高统计与分析

    美国总统身高统计与分析 1 安装依赖 2 下载数据集 3 数据处理 4 结果展示 1 安装依赖 pip install pandas pip install numpy pip install matplotlib 2 下载数据集 链接 h
  • PHICOMM路由器无线扩展的设置方法(吐槽一下)

    家里使用的是电信宽带 电信光纤猫有两个网口 网口1直连家里的电视 网口2连接了一部TPLINK路由器 设置了无线wifi 供家里的手机使用wifi 最近在卧室新增了一台台式电脑 用来在家里业余时间学习的 从客厅到卧室距离不长 但是因为家里面
  • 了解以及区分物理机,虚拟机(hypervisor/VMM) 和 容器(Docker)的适用场景

    了解以及区分物理机 虚拟机hypervisor VMM 和 容器Docker的适用场景 Abbreviations 物理机和虚拟机以及容器的区别 动机motivation 为什么要有虚拟机 物理机 虚拟机 容器 虚拟机的种类以及他们的本质区
  • 【Eigen】基本和常用函数

    文章目录 简介 找不到头文件 Eigen 中矩阵的定义 Eigen 中矩阵的使用方法 Eigen 中常用矩阵生成 Eigen 中矩阵分块 Eigen 中矩阵元素交换 Eigen 中矩阵转置 Eigen 中矩阵乘积 Eigen 中矩阵元素操作
  • Selenium自动化测试 —— 通过cookie绕过验证码的操作!

    验证码的处理 对于web应用 很多地方比如登录 发帖都需要输入验证码 类型也多种多样 登录 核心操作过程中 系统会产生随机的验证码图片 进行验证才能进行后续操作 解决验证码的方法如下 1 开发做个万能验证码 推荐 2 测试环境关闭验证码功能
  • Appium+Python自动化测试(一)--环境搭建

    Appium简介 Appium是一个自动化测试开源工具 支持IOS和Android平台上的移动原生应用 移动Web应用和混合应用 所谓的 移动原生应用 是指那些用IOS或者Android SDK写的应用 所谓的 移动Web应用 是指使用移动
  • VulnHub_Jangow: 1.0.1

    本文内容涉及程序 技术原理可能带有攻击性 仅用于安全研究和教学使用 务必在模拟环境下进行实验 请勿将其用于其他用途 因此造成的后果自行承担 如有违反国家法律则自行承担全部法律责任 与作者及分享者无关 主机信息 kali 192 168 31
  • Mysql超时重连解决方案3: 配置c3p0连接池(终极方案)

    前面的文章中 我介绍了修改mysql默认超时时间和配置proxool连接池的方法来解决Mysql超时重连的问题 方案1不推荐 它并没有从根本上解决问题 方案2可用 但配置相对复杂 所有才有了方案3 它既解决了关键问题 并且配置简单易懂 c3
  • Retrofit源码解析三——对接口方法参数注解的处理

    private Nullable ParameterHandler result null if annotations null for Annotation annotation annotations 核心就是这一句 实际上就是把前面
  • Firefox意外的服务器响应,WebSockets的无法解决的“意外地得到了延续帧”错误(Websockets unresolva...

    我知道了 事实证明 我当初采用的代码放在一个NULL字符后的握手响应报头的新行后 我没有注意到这一点 它看起来像一个 浏览器移动所有所接收的WebSocket消息通过离开单个NULL字符在前一次的认证响应被处理的字符缓冲区 以及b 这不是一
  • 2020美赛E题解题思路方法:淹溺在塑料中

    自20世纪50年代以来 由于塑料的用途多种多样 如食品包装 消费品 医疗器械和建筑等 塑料制造业呈指数级增长 虽然有显著的好处 但与塑料产量增加有关的负面影响也受到关注 塑料制品不易分解 难以处理 只有大约9 的塑料被回收利用 1 每年大约
  • Git命令参考手册

    git init 初始化本地git仓库 创建新仓库 git config global user name xxx 配置用户名 git config global user email xxx xxx com 配置邮件 git config
  • [NOIP1998 普及组] 阶乘之和

    题目描述 用高精度计算出 S 1 2 3 n n 50 其中 表示阶乘 定义为 n n n 1 n 2 1 例如 5 5 4 3 2 1 120 输入格式 一个正整数 n 输出格式 一个正整数 S 表示计算结果 输入输出样例 输入 1 3
  • 华为机试题:HJ107 求解立方根(python)

    文章目录 1 题目描述 2 Python3实现 3 知识点详解 1 input 获取控制台 任意形式 的输入 输出均为字符串类型 1 1 input 与 list input 的区别 及其相互转换方法 2 print 打印输出 3 whil
  • MyBatis中Like模糊查询的几种写法和注意点

    目录 友情提醒 第一章 Mybatis中SQL语句的模糊查询 1 1 第一种方式 直接双引号拼接 1 2 第二种方式 数据库为MySQL时用CONCAT 函数 1 3 第三种方式 bind元素 友情提醒 先看文章目录 大致了解知识点结构 直
  • spring cloud alibaba 学习(三)Nacos-NacosNamingService初始化流程

    1 NacosServiceManager 的创建 Configuration proxyBeanMethods false ConditionalOnDiscoveryEnabled ConditionalOnNacosDiscovery