当前位置: 首页 > news >正文

【深入理解SpringCloud微服务】深入理解nacos配置中心(二)——客户端启动源码分析

【深入理解SpringCloud微服务】深入理解nacos配置中心(二)——客户端启动源码分析

  • 服务端启动原理回顾
  • 源码解析
    • SpringBoot如何调用到PropertySourceLocator的locate()方法
    • NacosPropertySourceLocator#locate()
      • NacosPropertySourceLocator#loadNacosDataIfPresent()
      • NacosPropertySourceBuilder#build()
      • NacosConfigService#getConfig()

服务端启动原理回顾

在上一篇的《宏观理解nacos配置中心原理》的文章中,我们提到SpringBoot在启动之后会调用PropertySourceLocator的locate()方法获取配置信息。
在这里插入图片描述
PropertySourceLocator的locate()方法是用于获取配置信息,具体如何获取由实现这个接口的实现类去实现。可以通过RPC从远程获取,或者读取本地某个文件,也可以查询数据库,但是这个接口规定返回的是PropertySource对象。

于是nacos就实现了一个NacosPropertySourceLocator。

在这里插入图片描述

NacosPropertySourceLocator的locate()方法里面通过NacosConfigService向nacos服务端发起RPC远程调用获取配置信息,然后把获取到的配置信息放入CompositePropertySource对象返回。

源码解析

SpringBoot如何调用到PropertySourceLocator的locate()方法

PropertySourceLocator的locate()方法是从prepareContext()方法调用进去的,我们现在SpringApplication的run()方法中找到prepareContext()方法。

	public ConfigurableApplicationContext run(String... args) {...try {...context = createApplicationContext();...prepareContext(context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);...}catch (...) {...}...return context;}

prepareContext()就在refreshContext()方法前调用。

在这里插入图片描述

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {context.setEnvironment(environment);...applyInitializers(context);...}

prepareContext方法中会把Environment对象设置到Spring容器中,然后调用applyInitializers方法。

在这里插入图片描述

	protected void applyInitializers(ConfigurableApplicationContext context) {for (ApplicationContextInitializer initializer : getInitializers()) {...initializer.initialize(context);}}

applyInitializers方法会获取所有的ApplicationContextInitializer,这些ApplicationContextInitializer都是在SpringApplication初始化的时候加载的。

在这里插入图片描述

这里就会调用到PropertySourceBootstrapConfiguration#initialize()方法,里面就会调用到PropertySourceLocator的locate方法。

	public void initialize(ConfigurableApplicationContext applicationContext) {// 创建一个CompositePropertySource对象CompositePropertySource composite = new CompositePropertySource(BOOTSTRAP_PROPERTY_SOURCE_NAME);...// 从Spring容器中获取environment对象ConfigurableEnvironment environment = applicationContext.getEnvironment();// 遍历所有的PropertySourceLocatorfor (PropertySourceLocator locator : this.propertySourceLocators) {PropertySource<?> source = null;// 调用PropertySourceLocator的locate方法获取配置信息// 返回PropertySource对象source = locator.locate(environment);...// PropertySource放入到CompositePropertySource中composite.addPropertySource(source);empty = false;}if (!empty) {// 获取到environment对象中的MutablePropertySources对象MutablePropertySources propertySources = environment.getPropertySources();...// 把CompositePropertySource放入MutablePropertySources对象中insertPropertySources(propertySources, composite);...}}

首先创建一个CompositePropertySource对象,用于存放每个PropertySourceLocator的locate方法返回的PropertySource对象。

然后循环遍历每一个PropertySourceLocator,调用locate方法,返回的PropertySource对象放入CompositePropertySource中。

最后从environment对象中取出MutablePropertySources对象,把CompositePropertySource放入MutablePropertySources中。

在这里插入图片描述

NacosPropertySourceLocator#locate()

nacos在spring-cloud-alibaba-nacos-config中的spring.factories文件中指定了自己的配置类NacosConfigBootstrapConfiguration,NacosConfigBootstrapConfiguration中通过@Bean注解配置了NacosPropertySourceLocator。

@Configuration
@ConditionalOnProperty(name = "spring.cloud.nacos.config.enabled", matchIfMissing = true)
public class NacosConfigBootstrapConfiguration {...@Beanpublic NacosPropertySourceLocator nacosPropertySourceLocator(NacosConfigProperties nacosConfigProperties) {return new NacosPropertySourceLocator(nacosConfigProperties);}}

在这里插入图片描述

由于nacos向Spring注册了自己的PropertySourceLocator——NacosPropertySourceLocator,那么自然就会调用到NacosPropertySourceLocator的locate方法。

	@Overridepublic PropertySource<?> locate(Environment env) {...// 创建一个CompositePropertySource对象CompositePropertySource composite = new CompositePropertySource(NACOS_PROPERTY_SOURCE_NAME);// 加载共享配置loadSharedConfiguration(composite);// 加载扩展配置loadExtConfiguration(composite);// 加载应用程序配置loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);// 返回CompositePropertySource对象return composite;}

我们知道nacos是有共享配置、扩展配置和应用程序配置之分的,这里就是分别加载共享配置、扩展配置和应用程序配置,越往后配置的优先级越高。

在这里插入图片描述

这三个方法,都会调用到loadNacosDataIfPresent()方法去获取配置。

在这里插入图片描述

NacosPropertySourceLocator#loadNacosDataIfPresent()

	private void loadNacosDataIfPresent(final CompositePropertySource composite,...// 调用loadNacosPropertySource方法获取配置信息,返回NacosPropertySourceNacosPropertySource propertySource = this.loadNacosPropertySource(dataId, group,fileExtension, isRefreshable);// NacosPropertySource放入CompositePropertySourcethis.addFirstPropertySource(composite, propertySource, false);}

NacosPropertySourceLocator的loadNacosDataIfPresent()调用loadNacosPropertySource方法获取配置信息,返回NacosPropertySource,然后把NacosPropertySource放入CompositePropertySource。

在这里插入图片描述

	private NacosPropertySource loadNacosPropertySource(final String dataId,final String group, String fileExtension, boolean isRefreshable) {...return nacosPropertySourceBuilder.build(dataId, group, fileExtension,isRefreshable);}

loadNacosPropertySource方法调用NacosPropertySourceBuilder的build方法。

在这里插入图片描述

NacosPropertySourceBuilder#build()

	NacosPropertySource build(String dataId, String group, String fileExtension,boolean isRefreshable) {Map<String, Object> p = loadNacosData(dataId, group, fileExtension);NacosPropertySource nacosPropertySource = new NacosPropertySource(group, dataId,p, ...);...return nacosPropertySource;}

NacosPropertySourceBuilder的build方法中调用loadNacosData方法获取配置信息,loadNacosData方法返回的是一个Map结构,然后把Map封装成NacosPropertySource返回。

在这里插入图片描述

	private Map<String, Object> loadNacosData(String dataId, String group,String fileExtension) {String data = null;try {// 调用NacosConfigService获取配置信息data = configService.getConfig(dataId, group, timeout);...// 获取到的配置信息转成MapMap<String, Object> dataMap = NacosDataParserHandler.getInstance().parseNacosData(data, fileExtension);return dataMap == null ? EMPTY_MAP : dataMap;}...}

在NacosPropertySourceBuilder的loadNacosData方法获中,调用NacosConfigService的getConfig方法获取配置信息,然后把返回的配置信息转成Map结构,最后返回该Map。

在这里插入图片描述

NacosConfigService#getConfig()

    public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {return getConfigInner(namespace, dataId, group, timeoutMs);}

NacosConfigService的getConfig()调用getConfigInner方法。

在这里插入图片描述

    private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {...// 优先从本地配置文件获取String content = LocalConfigInfoProcessor.getFailover(worker.getAgentName(), dataId, group, tenant);if (content != null) {...return content;}try {// 本地没有,再调用ClientWorker从远程服务器获取ConfigResponse response = worker.getServerConfig(dataId, group, tenant, timeoutMs, false);cr.setContent(response.getContent());...content = cr.getContent();return content;} catch (...) {...}...}

NacosConfigService的getConfigInner方法首先从本地配置文件获取,如果本地没有才调用ClientWorker的getServerConfig从远程服务器获取。

在这里插入图片描述

然后ClientWorker的getServerConfig方法会调用到ConfigRpcTransportClient#queryConfig()方法

        @Overridepublic ConfigResponse queryConfig(String dataId, String group, String tenant, long readTimeouts, boolean notify)throws NacosException {// 创建ConfigQueryRequest类型的请求对象ConfigQueryRequest request = ConfigQueryRequest.build(dataId, group, tenant);...// 创建RpcClient对象,用于发起远程调用RpcClient rpcClient = getOneRunningClient();...// 发起GRPC远程调用ConfigQueryResponse response = (ConfigQueryResponse) requestProxy(rpcClient, request, readTimeouts);...if (response.isSuccess()) {// 保存到本地配置文件LocalConfigInfoProcessor.saveSnapshot(this.getName(), dataId, group, tenant, response.getContent());...return configResponse;}...}

ConfigRpcTransportClient的queryConfig方法发起GRPC远程调用请求远程服务器获取配置内容,然后把获取到的配置内容保存到本地配置文件,那么下次再次获取时,就不需要发起远程调用请求从远程服务器获取了,而是直接取本地配置文件。

在这里插入图片描述

        private Response requestProxy(RpcClient rpcClientInner, Request request, long timeoutMills)throws NacosException {...// 调用RpcClient的request方法,发起GRPC远程调用return rpcClientInner.request(request, timeoutMills);}

requestProxy方法里面就是调用调用RpcClient的request方法,发起GRPC远程调用,里面依赖到了grpc的API,我们就不往下看grpc的逻辑了。

在这里插入图片描述

以上便是nacos配置中心客户端启动源码的整体流程,下面是源码分析的整体流程图:

在这里插入图片描述


http://www.mrgr.cn/news/21411.html

相关文章:

  • LLM大模型:将爬虫与大语言模型结合
  • 部署若依Spring boot项目
  • 基于javaweb的茶园茶农文化交流平台的设计与实现(源码+L文+ppt)
  • HTML 基础,尚优选网站设计开发(二)
  • C++ 上位软件通过Snap7开源库访问西门子S7-1200/S7-1500数据块的方法
  • Java集合
  • 【每日刷题】Day112
  • Danbooru风格图片分享平台szurubooru
  • 【2024高教社杯国赛A题】数学建模国赛建模过程+完整代码论文全解全析
  • 如何从硬盘恢复已删除/丢失的文件?硬盘恢复已删除的文件技巧
  • 分布式光伏的劣势
  • 数据链路层
  • (五十九)第 9 章 查找(B 树)
  • 非空约束(Not Null)
  • 数字化平台跨界融合增值:新起点与新机遇
  • c++修炼之路之特殊类设计与类型转换
  • LoRA微调基础知识点
  • 饲料加工机器设备有哪些组成部分
  • 微信小程序和普通网页有什么不同
  • 【阿里云】个人认证与公司认证