nacos服务注册源码过程阅读

news2024/10/7 1:52:15

准备部分

在这里插入图片描述

这是在真正调用注册实例的方法之前,需要使用到的对象的关系图。

源码跟踪

NacosServiceRegistryAutoConfiguration类

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
		matchIfMissing = true)
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
		AutoServiceRegistrationAutoConfiguration.class,
		NacosDiscoveryAutoConfiguration.class })
public class NacosServiceRegistryAutoConfiguration {

	@Bean
	public NacosServiceRegistry nacosServiceRegistry(
	 //  在spring.factories中,有个自动创建的类是 NacosServiceAutoConfiguration,这个类里创建了 NacosServiceManager 对象,也就是对应这里的第一个参数
			NacosServiceManager nacosServiceManager, 
			NacosDiscoveryProperties nacosDiscoveryProperties) {   //  取的配置文件
		return new NacosServiceRegistry(nacosServiceManager, nacosDiscoveryProperties);
	}

	@Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
	public NacosRegistration nacosRegistration(
			ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers,  // 不知道是个啥,感觉不是重点所以没看
			NacosDiscoveryProperties nacosDiscoveryProperties,  // 配置文件
			ApplicationContext context) {   // spring容器创建的
		return new NacosRegistration(registrationCustomizers.getIfAvailable(),
				nacosDiscoveryProperties, context);
	}

	@Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
	这个是才是重点对象
	public NacosAutoServiceRegistration nacosAutoServiceRegistration(
			NacosServiceRegistry registry,  // 上面第一个方法创建的Bean
			AutoServiceRegistrationProperties autoServiceRegistrationProperties,    // 取的配置文件中的值
			NacosRegistration registration) {  // 上面第二个方法创建的Bean
		return new NacosAutoServiceRegistration(registry,
				autoServiceRegistrationProperties, registration);
	}

}

AbstractAutoServiceRegistration类

直接看NacosAutoServiceRegistration继承的这个抽象类

	@Override
	@SuppressWarnings("deprecation")
	//  NacosAutoServiceRegistration类有实现ApplicationListener<WebServerInitializedEvent>,所以会监听到WebServerInitializedEvent事件
	public void onApplicationEvent(WebServerInitializedEvent event) {
		bind(event);
	}


	public void bind(WebServerInitializedEvent event) {
		ApplicationContext context = event.getApplicationContext();
		if (context instanceof ConfigurableWebServerApplicationContext) {
			if ("management".equals(((ConfigurableWebServerApplicationContext) context).getServerNamespace())) {
				return;
			}
		}
		this.port.compareAndSet(0, event.getWebServer().getPort());
		this.start();
	}
	

public void start() {
		if (!isEnabled()) {
			if (logger.isDebugEnabled()) {
				logger.debug("Discovery Lifecycle disabled. Not starting");
			}
			return;
		}

		if (!this.running.get()) {
		//  NacosServiceManager类中的 onInstancePreRegisteredEvent 方法上有@EventListener,会监听到这个预注册事件,具体不知道逻辑,看变量名称好像缓存		    	                  用的
			this.context.publishEvent(new InstancePreRegisteredEvent(this, getRegistration()));
			// 会调用register方法
			register();
			if (shouldRegisterManagement()) {
				registerManagement();
			}
			this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration()));
			this.running.compareAndSet(false, true);
		}

	}

NacosServiceRegistry类

一直溯源register方法,会看到NacosServiceRegistry类中的register(Registration registration)方法,

@Override
	public void register(Registration registration) {

		if (StringUtils.isEmpty(registration.getServiceId())) {
			log.warn("No service to register for nacos client...");
			return;
		}
		//  这里的namingService()溯源会看到创建这个NamingService 用到了反射
		NamingService namingService = namingService();
		// serviceId 其实就是spring.application.name值
		String serviceId = registration.getServiceId();
		String group = nacosDiscoveryProperties.getGroup();
		
		// 直接new一个Instance对象
		Instance instance = getNacosInstanceFromRegistration(registration);

		try {
			namingService.registerInstance(serviceId, group, instance);
			log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
					instance.getIp(), instance.getPort());
		}
		catch (Exception e) {
			if (nacosDiscoveryProperties.isFailFast()) {
				log.error("nacos registry, {} register failed...{},", serviceId,
						registration.toString(), e);
				rethrowRuntimeException(e);
			}
			else {
				log.warn("Failfast is false. {} register failed...{},", serviceId,
						registration.toString(), e);
			}
		}
	}

创建NamingService的具体代码:

    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 var4) {
            throw new NacosException(-400, var4);
        }
    }

NacosNamingService类

    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    //  这里校验的就是配置的心跳间隔和心跳超时,ip删除超时三个参数的值的大小关系,心跳间隔必须比这两个都要小
        NamingUtils.checkInstanceIsLegal(instance);
        String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
        //  如果是临时实例,就会开一个心跳线程,不设置事件默认应该是5s的延迟
        if (instance.isEphemeral()) {
            BeatInfo beatInfo = this.beatReactor.buildBeatInfo(groupedServiceName, instance);
            this.beatReactor.addBeatInfo(groupedServiceName, beatInfo);
        }

        this.serverProxy.registerService(groupedServiceName, groupName, instance);
    }

NamingProxy类

    public String callServer(String api, Map<String, String> params, Map<String, String> body, String curServer, String method) throws NacosException {
        long start = System.currentTimeMillis();
        long end = 0L;
        this.injectSecurityInfo(params);
        Header header = this.builderHeader();
        String url;
        if (!curServer.startsWith("https://") && !curServer.startsWith("http://")) {
            if (!IPUtil.containsPort(curServer)) {
                curServer = curServer + ":" + this.serverPort;
            }

            url = NamingHttpClientManager.getInstance().getPrefix() + curServer + api;
        } else {
            url = curServer + api;
        }

        try {
        // 这里的nacosRestTemplate 点进去溯源之后会发现 
            HttpRestResult<String> restResult = this.nacosRestTemplate.exchangeForm(url, header, Query.newInstance().initParams(params), body, method, String.class);
            end = System.currentTimeMillis();
            MetricsMonitor.getNamingRequestMonitor(method, url, String.valueOf(restResult.getCode())).observe((double)(end - start));
            if (restResult.ok()) {
                return (String)restResult.getData();
            } else if (304 == restResult.getCode()) {
                return "";
            } else {
                throw new NacosException(restResult.getCode(), restResult.getMessage());
            }
        } catch (Exception var13) {
            LogUtils.NAMING_LOGGER.error("[NA] failed to request", var13);
            throw new NacosException(500, var13);
        }
    }
// 先是在NamingProxy中显式创建NacosRestTemplate 对象
private final NacosRestTemplate nacosRestTemplate = NamingHttpClientManager.getInstance().getNacosRestTemplate();


NamingHttpClientManager类

//  这里传入的参数其实是NamingHttpClientFactory对象,并且这个对象是继承了AbstractHttpClientFactory抽象类的
    public NacosRestTemplate getNacosRestTemplate() {
        return HttpClientBeanHolder.getNacosRestTemplate(HTTP_CLIENT_FACTORY);
    }


HttpClientBeanHolder类

  public static NacosRestTemplate getNacosRestTemplate(HttpClientFactory httpClientFactory) {
        if (httpClientFactory == null) {
            throw new NullPointerException("httpClientFactory is null");
        }
        String factoryName = httpClientFactory.getClass().getName();
        NacosRestTemplate nacosRestTemplate = SINGLETON_REST.get(factoryName);
        if (nacosRestTemplate == null) {
            synchronized (SINGLETON_REST) {
                nacosRestTemplate = SINGLETON_REST.get(factoryName);
                if (nacosRestTemplate != null) {
                    return nacosRestTemplate;
                }
                //  如果SINGLETON_REST 这个集合中没有找到,会走到这个方法,会发现 参数传过来的 httpClientFactory是个接口,并且有两个实现类,分别是AbstractApacheHttpClientFactory和AbstractHttpClientFactory,因为知道入参其实就是NamingHttpClientFactory,并且继承了AbstractHttpClientFactory
                nacosRestTemplate = httpClientFactory.createNacosRestTemplate();
                SINGLETON_REST.put(factoryName, nacosRestTemplate);
            }
        }
        return nacosRestTemplate;
    }


AbstractHttpClientFactory类

        HttpClientConfig httpClientConfig = buildHttpClientConfig();
        // 这里就知道NacosRestTemplate中的HttpClientRequest属性其实是  JdkHttpClientRequest实例对象,
        final JdkHttpClientRequest clientRequest = new JdkHttpClientRequest(httpClientConfig);
        
        // enable ssl
        initTls(new BiConsumer<SSLContext, HostnameVerifier>() {
            @Override
            public void accept(SSLContext sslContext, HostnameVerifier hostnameVerifier) {
                clientRequest.setSSLContext(loadSSLContext());
                clientRequest.replaceSSLHostnameVerifier(hostnameVerifier);
            }
        }, new TlsFileWatcher.FileChangeListener() {
            @Override
            public void onChanged(String filePath) {
                clientRequest.setSSLContext(loadSSLContext());
            }
        });
        
        return new NacosRestTemplate(assignLogger(), clientRequest);
    }

NacosRestTemplate类

在上面NamingProxy中一顿点击之后,会调用到NacosRestTemplate的execute方法,如下

    private <T> HttpRestResult<T> execute(String url, String httpMethod, RequestHttpEntity requestEntity,
            Type responseType) throws Exception {
        URI uri = HttpUtils.buildUri(url, requestEntity.getQuery());
        if (logger.isDebugEnabled()) {
            logger.debug("HTTP method: {}, url: {}, body: {}", httpMethod, uri, requestEntity.getBody());
        }
        
        ResponseHandler<T> responseHandler = super.selectResponseHandler(responseType);
        HttpClientResponse response = null;
        try {
        /// 上面溯源得到的  JdkHttpClientRequest  对应的就是this.requestClient(),因为上面可以看到调用NacosRestTemplate的构造函数,传入的是JdkHttpClientRequest  
            response = this.requestClient().execute(uri, httpMethod, requestEntity);
            return responseHandler.handle(response);
        } finally {
            if (response != null) {
                response.close();
            }
        }
    }

之后就是使用HttpURLConnection实际发情请求,并且处理Response了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/30315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言学习之路(基础篇)—— 内存管理

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 作用域 C语言变量的作用域分为&#xff1a; 代码块作用域(代码块是{}之间的一段代码)函数作用域文件作用域 1) 局部变量 生命周期&#xff1a;…

Python 基础(一):初识 Python

文章目录Python是什么解释型语言Python 之父Python 名字的由来Python 的应用领域人生苦短&#xff0c;我用 Python大家好&#xff0c;我是水滴~~ 本文对 Python 做了一个初步的介绍&#xff0c;并了解 Python 的作者、名字由来、应用领域等。 Python是什么 Python 是一种面向…

什么是软件测试?

什么是软件测试&#xff1f; 软件测试的定义&#xff1a;在一定条件下对软件进行操作&#xff0c;发现软件的问题&#xff0c;提高软件的质量。 软件测试在开发中的有着重要地位。软件测试在各阶段的完成相应的任务&#xff0c;需求测试&#xff0c;架构测试&#xff0c;详细测…

C语言条件运算符——三元表达式例题(素材来自C技能树)

&#x1f4d1;三目运算符 三目运算符也叫条件运算符、三元运算符&#xff0c;是由一个问号和一个冒号组成。语法&#xff1a;表达式1?表达式2:表达式3;语义&#xff1a;先执行表达式1&#xff0c;如果表达式1的结果如果为真&#xff0c;那么执行表达式2&#xff0c;并且这个整…

level2接口有什么用?是如何获取A股行情数据的?

目前国内有很多数据团队专门为金融机构、学术团体和量化研究者们提供的本地量化金融数据服务&#xff0c;那么最常见的就是通达信、同花顺等团队&#xff0c;他们开发出来的level2接口可快速查看和计算金融数据&#xff0c;无障碍解决本地、Web、金融终端调用数据的需求。为了满…

彻底解决 K8s 节点本地存储被撑爆的问题

一、存储的内容 要解决存储使用过多的问题&#xff0c;就得先了解存储中都保存了些什么内容&#xff0c;否则解决不了问题&#xff0c;还可能带来更多的风险。 1.1、镜像 容器要在节点上运行&#xff0c;kubelet 首先要拉取容器镜像到节点本地&#xff0c;然后再根据镜像创建…

3分钟读懂RD与RT

Route-Distinguisher&#xff08;后简称"RD"&#xff09;&#xff0c;Route-Target&#xff08;后简称"RT"&#xff09;经常出现在EVPN、MPLS VPN中&#xff0c;但它们是完全不同的两个概念&#xff0c;初学者往往难以区分两者的差异。学霸题&#xff1a;区…

Jmeter入门

性能测试&#xff1a;模拟多个用户的操作对服务器硬件性能的影响 TPS&#xff1a;Transaction per Second&#xff0c;每秒事务处理能力 RT&#xff1a;Response Time&#xff0c;响应时间 安装 由于本人只有window系统&#xff0c;故只讲解win下的安装 安装JDK 下载地址&a…

2023年最热门的网络安全岗位分析

大数据、人工智能、云计算、物联网、5G等新兴技术的高速发展&#xff0c;蒸蒸日上。但是随之也出现了许多问题&#xff0c;比如&#xff1a;政府单位、企业、个人信息泄露&#xff0c;网络安全问题日益严峻&#xff0c;网络空间安全建设刻不容缓。 网络安全人才需求量巨大&…

双核驱动,合力共进,郁锦香与凯里亚德酒店强强联合释放多元化商业价值

近日&#xff0c;以“清风雅茗 亨嘉之会”为主题的2022锦江酒店&#xff08;中国区&#xff09;厦门站品牌投资品鉴会圆满落幕&#xff0c;众多投资人和酒店品牌方负责人齐聚一堂&#xff0c;在充满文艺气息的滨海城市厦门&#xff0c;感受精致、愉悦的慢生活。在品牌见面环节&…

NodeJs实战-Express构建照片存储网站(1)-ejs视图引擎填充数据

ejs视图引擎填充数据express 生成项目安装 express-generator生成项目程序结构理解项目结构生成的文件的含义视图渲染填充照片数据增加路由器修改 app.js修改 routes增加对应的视图页面路由器 res.render 查找视图逻辑新增文件之后的项目结构图效果图项目地址express 生成项目 …

kali Linux常用快捷键及vim的基本使用

kali Linux 系统快捷键 Ctrl Alt T &#xff1a;打开一个新的命令行终端。 如果是在桌面打开的是这种情况 Ctrl C 复制。 Ctrl Z 撤消。 Ctrl S &#xff1a;保存 Ctrl Q &#xff1a;退出。 终端快捷键 TAB &#xff1a;补全命令。 Ctrl &#xff1a;放大文字…

Netty系列(一):Springboot整合Netty,自定义协议实现

Netty是由JBOSS提供的一个java开源框架&#xff0c;现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具&#xff0c;用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说&#xff0c;Netty 是一个基于NIO的客户、服务器端的编程框架&…

目标检测论文解读复现之十六:基于改进YOLOv5的小目标检测算法

前言 此前出了目标改进算法专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读最新目标检测算法论文&#xff0c…

Java项目使用intellij-IDEA查看依赖包版本是否有冲突(方法及工具)

编译器及版本idea-ultimate依赖管理工具maven 第一个是idea本身的 Step1&#xff1a;点击右侧的maven Step2&#xff1a;右键依赖项&#xff0c;点击分析依赖关系 Step3&#xff1a;可以在模块名位置进行切换&#xff0c;左侧三角的标志则表示该包引入了多个版本&#xff…

【云原生】Docker网络原理及Cgroup硬件资源占用控制

内容预知 1.dockers的网络模式 获取容器的进程号 docker网络模式的特性 1.1 host主机模式 1.2 container模式 1.3 none模式 1.4 bridge 桥接模式 1.5 容器的自定义网络 &#xff08;1&#xff09;未创建自定义网络时&#xff0c;创建指定IP容器的测试 &#xff08;2&a…

双坐标轴柱状图

双坐标轴柱状图 setwd(“H:/分析评价 20220531/6-分析过程”) #设置工作路径 library(xlsx)#加载excel文件包 #---------------------------------------------------------------------------------------------------------- tiff(file“1-占比.tiff”,res600,width6000,hei…

负载均衡有哪些?

目录 【一】前言 【二】负载均衡分类 2.1 DNS 2.2 硬件负载均衡 2.3 软件负载均衡 2.4 组合负载均衡 【三】负载均衡算法 3.1 负载均衡算法分类 3.2 轮询 3.3 加权轮询 3.4 负载最低优先 3.5 性能最优类 3.6 Hash 【四】总结 【一】前言 在互联网尤其是移动互联…

【前沿技术RPA】 一文了解UiPath的项目活动设置

&#x1f40b;作者简介&#xff1a;博主是一位.Net开发者&#xff0c;同时也是RPA和低代码平台的践行者。 &#x1f42c;个人主页&#xff1a;会敲键盘的肘子 &#x1f430;系列专栏&#xff1a;UiPath &#x1f980;专栏简介&#xff1a;UiPath在传统的RPA&#xff08;Robotic…

【计算机组成原理Note】5.2 指令周期的数据流

5.2 指令周期的数据流 5.2.1 指令周期 指令周期&#xff1a;CPU从主存中每取出并执行一条指令所需的全部时间。 指令周期&#xff1a;常常用若干机器周期来表示&#xff0c;机器周期又叫CPU周期。 一个机器周期又包含若干时钟周期(也称为节拍、T周期或CPU时钟周期&#xff…