我的编程空间,编程开发者的网络收藏夹
学习永远不晚

SpringCloudAlibabaNacosConfig加载配置详解流程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

SpringCloudAlibabaNacosConfig加载配置详解流程

1、加载节点

SpringBoot启动时,会执行这个方法:SpringApplication#run,这个方法中会调prepareContext来准备上下文,这个方法中调用了applyInitializers方法来执行实现了ApplicationContextInitializer接口的类的initialize方法。其中包括PropertySourceBootstrapConfiguration#initialize 来加载外部的配置。

@Autowired(required = false)
private List<PropertySourceLocator> propertySourceLocators = new ArrayList<>();
public void initialize(ConfigurableApplicationContext applicationContext) {
	...
   for (PropertySourceLocator locator : this.propertySourceLocators) {
       //载入PropertySource
      Collection<PropertySource<?>> source = locator.locateCollection(environment);
      ...
   }
   ...
}
//org.springframework.cloud.bootstrap.config.PropertySourceLocator#locateCollection
default Collection<PropertySource<?>> locateCollection(Environment environment) {
    return locateCollection(this, environment);
}
//org.springframework.cloud.bootstrap.config.PropertySourceLocator#locateCollection
static Collection<PropertySource<?>> locateCollection(PropertySourceLocator locator, Environment environment) {
    //执行locate方法,将PropertySource加载进来
    PropertySource<?> propertySource = locator.locate(environment);
    ...
}

这个类中会注入实现了PropertySourceLocator接口的类,在nacos中是NacosPropertySourceLocator。

在initialize方法中会执行NacosPropertySourceLocator的locate方法,将NacosPropertySource加载进来。

2、NacosPropertySourceLocator的注册

NacosPropertySourceLocator在配置类NacosConfigBootstrapConfiguration中注册。

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

在这里会依次注册NacosConfigProperties,NacosConfigManager,NacosPropertySourceLocator。

3、加载

//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#locate
public PropertySource<?> locate(Environment env) {
   nacosConfigProperties.setEnvironment(env);
    //获取ConfigService
   ConfigService configService = nacosConfigManager.getConfigService();

   if (null == configService) {
      log.warn("no instance of config service found, can't load config from nacos");
      return null;
   }
   long timeout = nacosConfigProperties.getTimeout();
    //构建nacosPropertySourceBuilder
   nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService,
         timeout);
   String name = nacosConfigProperties.getName();
	//获取dataIdPrefix,一次从prefix,name,spring.application.name中获取
   String dataIdPrefix = nacosConfigProperties.getPrefix();
   if (StringUtils.isEmpty(dataIdPrefix)) {
      dataIdPrefix = name;
   }
   if (StringUtils.isEmpty(dataIdPrefix)) {
      dataIdPrefix = env.getProperty("spring.application.name");
   }
	//构建CompositePropertySource:NACOS
   CompositePropertySource composite = new CompositePropertySource(
         NACOS_PROPERTY_SOURCE_NAME);
	//加载share 配置
   loadSharedConfiguration(composite);
   //加载extention 配置
   loadExtConfiguration(composite);
    //加载application配置
   loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
   return composite;
}

3.1、加载share

private void loadSharedConfiguration(
      CompositePropertySource compositePropertySource) {
   //获取share节点的配置信息
   List<NacosConfigProperties.Config> sharedConfigs = nacosConfigProperties
         .getSharedConfigs();
    //如果不为空,加载
   if (!CollectionUtils.isEmpty(sharedConfigs)) {
      checkConfiguration(sharedConfigs, "shared-configs");
      loadNacosConfiguration(compositePropertySource, sharedConfigs);
   }
}

加载配置,公用方法

//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosConfiguration
private void loadNacosConfiguration(final CompositePropertySource composite,
                                    List<NacosConfigProperties.Config> configs) {
    for (NacosConfigProperties.Config config : configs) {
        loadNacosDataIfPresent(composite, config.getDataId(), config.getGroup(),
                               NacosDataParserHandler.getInstance()
                               .getFileExtension(config.getDataId()),
                               config.isRefresh());
    }
}
//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosDataIfPresent
private void loadNacosDataIfPresent(final CompositePropertySource composite,
      final String dataId, final String group, String fileExtension,
      boolean isRefreshable) {
   if (null == dataId || dataId.trim().length() < 1) {
      return;
   }
   if (null == group || group.trim().length() < 1) {
      return;
   }
    //加载NacosPropertySource,后面也会用这个方法
   NacosPropertySource propertySource = this.loadNacosPropertySource(dataId, group,
         fileExtension, isRefreshable);
    //将NacosPropertySource放入第一个
   this.addFirstPropertySource(composite, propertySource, false);
}

加载NacosPropertySource

//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosPropertySource
private NacosPropertySource loadNacosPropertySource(final String dataId,
      final String group, String fileExtension, boolean isRefreshable) {
   //标注@RefreshScope的类的数量不为0,且不允许自动刷新,从缓存加载nacos的配置
    if (NacosContextRefresher.getRefreshCount() != 0) {
      if (!isRefreshable) {
         return NacosPropertySourceRepository.getNacosPropertySource(dataId,
               group);
      }
   }
   return nacosPropertySourceBuilder.build(dataId, group, fileExtension,
         isRefreshable);
}

从缓存中加载

//NacosPropertySourceRepository
private final static ConcurrentHashMap<String, NacosPropertySource> NACOS_PROPERTY_SOURCE_REPOSITORY = new ConcurrentHashMap<>();
public static NacosPropertySource getNacosPropertySource(String dataId,
      String group) {
   return NACOS_PROPERTY_SOURCE_REPOSITORY.get(getMapKey(dataId, group));
}
public static String getMapKey(String dataId, String group) {
   return String.join(NacosConfigProperties.COMMAS, String.valueOf(dataId),
         String.valueOf(group));
}

NacosPropertySourceRepository中缓存了NacosPropertySource

获取配置并加入缓存

//com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#build
NacosPropertySource build(String dataId, String group, String fileExtension,
      boolean isRefreshable) {
    //获取配置
   List<PropertySource<?>> propertySources = loadNacosData(dataId, group,
         fileExtension);
    //包装成NacosPropertySource
   NacosPropertySource nacosPropertySource = new NacosPropertySource(propertySources,
         group, dataId, new Date(), isRefreshable);
    //加入缓存
   NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource);
   return nacosPropertySource;
}
//com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#loadNacosData
private List<PropertySource<?>> loadNacosData(String dataId, String group,
      String fileExtension) {
   String data = null;
   try {
       //获取配置
      data = configService.getConfig(dataId, group, timeout);
      if (StringUtils.isEmpty(data)) {
         log.warn(
               "Ignore the empty nacos configuration and get it based on dataId[{}] & group[{}]",
               dataId, group);
         return Collections.emptyList();
      }
      if (log.isDebugEnabled()) {
         log.debug(String.format(
               "Loading nacos data, dataId: '%s', group: '%s', data: %s", dataId,
               group, data));
      }
      return NacosDataParserHandler.getInstance().parseNacosData(dataId, data,
            fileExtension);
   }
   catch (NacosException e) {
      log.error("get data from Nacos error,dataId:{} ", dataId, e);
   }
   catch (Exception e) {
      log.error("parse data from Nacos error,dataId:{},data:{}", dataId, data, e);
   }
   return Collections.emptyList();
}
//com.alibaba.nacos.client.config.NacosConfigService#getConfig
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {
    return getConfigInner(namespace, dataId, group, timeoutMs);
}
//com.alibaba.nacos.client.config.NacosConfigService#getConfigInner
private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {
    group = blank2defaultGroup(group);
    ParamUtils.checkKeyParam(dataId, group);
    //声明响应
    ConfigResponse cr = new ConfigResponse();
    //设置dataId,tenant,group
    cr.setDataId(dataId);
    cr.setTenant(tenant);
    cr.setGroup(group);
    // use local config first
    //先从本地缓存中加载
    String content = LocalConfigInfoProcessor.getFailover(worker.getAgentName(), dataId, group, tenant);
    if (content != null) {
        LOGGER.warn("[{}] [get-config] get failover ok, dataId={}, group={}, tenant={}, config={}",
                worker.getAgentName(), dataId, group, tenant, ContentUtils.truncateContent(content));
        cr.setContent(content);
        String encryptedDataKey = LocalEncryptedDataKeyProcessor
                .getEncryptDataKeyFailover(agent.getName(), dataId, group, tenant);
        cr.setEncryptedDataKey(encryptedDataKey);
        configFilterChainManager.doFilter(null, cr);
        content = cr.getContent();
        return content;
    }
    try {
        //从服务器获取配置
        ConfigResponse response = worker.getServerConfig(dataId, group, tenant, timeoutMs, false);
        cr.setContent(response.getContent());
        cr.setEncryptedDataKey(response.getEncryptedDataKey());
        configFilterChainManager.doFilter(null, cr);
        content = cr.getContent();
        return content;
    } catch (NacosException ioe) {
        if (NacosException.NO_RIGHT == ioe.getErrCode()) {
            throw ioe;
        }
        LOGGER.warn("[{}] [get-config] get from server error, dataId={}, group={}, tenant={}, msg={}",
                worker.getAgentName(), dataId, group, tenant, ioe.toString());
    }
    LOGGER.warn("[{}] [get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}",
            worker.getAgentName(), dataId, group, tenant, ContentUtils.truncateContent(content));
    content = LocalConfigInfoProcessor.getSnapshot(worker.getAgentName(), dataId, group, tenant);
    cr.setContent(content);
    String encryptedDataKey = LocalEncryptedDataKeyProcessor
            .getEncryptDataKeyFailover(agent.getName(), dataId, group, tenant);
    cr.setEncryptedDataKey(encryptedDataKey);
    configFilterChainManager.doFilter(null, cr);
    content = cr.getContent();
    return content;
}

将NacosPropertySource加入composite的第一个

//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#addFirstPropertySource
private void addFirstPropertySource(final CompositePropertySource composite,
      NacosPropertySource nacosPropertySource, boolean ignoreEmpty) {
   if (null == nacosPropertySource || null == composite) {
      return;
   }
   if (ignoreEmpty && nacosPropertySource.getSource().isEmpty()) {
      return;
   }
   composite.addFirstPropertySource(nacosPropertySource);
}

3.2、加载extention

private void loadExtConfiguration(CompositePropertySource compositePropertySource) {
    //获取extention节点的配置信息
   List<NacosConfigProperties.Config> extConfigs = nacosConfigProperties
         .getExtensionConfigs();
    //如果不为空,加载
   if (!CollectionUtils.isEmpty(extConfigs)) {
      checkConfiguration(extConfigs, "extension-configs");
      loadNacosConfiguration(compositePropertySource, extConfigs);
   }
}

3.3、加载主配置文件

private void loadApplicationConfiguration(
      CompositePropertySource compositePropertySource, String dataIdPrefix,
      NacosConfigProperties properties, Environment environment) {
   //获取文件扩展名
   String fileExtension = properties.getFileExtension();
    //获取group
   String nacosGroup = properties.getGroup();
   // load directly once by default
    //加载nacos的配置
   loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup,
         fileExtension, true);
   // load with suffix, which have a higher priority than the default
    //加载带后缀的配置,优先级高于上一个
   loadNacosDataIfPresent(compositePropertySource,
         dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true);
   // Loaded with profile, which have a higher priority than the suffix
   for (String profile : environment.getActiveProfiles()) {
      String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
       //加载带profile,文件格式后缀的配置,优先级高于上一个
      loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
            fileExtension, true);
   }
}

这里会加载至少三个nacos上面的配置文件,按优先级依次为application,application.yaml,application-dev.yaml。

到此这篇关于Spring Cloud Alibaba Nacos Config加载配置详解流程的文章就介绍到这了,更多相关Spring Cloud Alibaba Nacos Config 内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

SpringCloudAlibabaNacosConfig加载配置详解流程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SpringBoot配置的加载流程详细分析

了解内部原理是为了帮助我们做扩展,同时也是验证了一个人的学习能力,如果你想让自己的职业道路更上一层楼,这些底层的东西你是必须要会的,这篇文章主要介绍了SpringBoot配置的加载流程
2023-01-06

SpringIOC BeanDefinition的加载流程详解

这篇文章主要为大家介绍了SpringIOC BeanDefinition的加载流程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

Spring加载加密的配置文件详解

本文实例为大家分享了Spring加载加密的配置文件,供大家参考,具体内容如下一、继承并实现自己的属性文件配置器类public
2023-05-31

SpringBootbean查询加载顺序流程详解

当你在项目启动时需要提前做一个业务的初始化工作时,或者你正在开发某个中间件需要完成自动装配时。你会声明自己的Configuration类,但是可能你面对的是好几个有互相依赖的Bean
2023-03-12

webpack loader配置全流程详解

前言1.主要目的为稍微梳理从配置到装载的流程。另外详解当然要加点源码提升格调(本人菜鸟,有错还请友善指正)2.被的WebPack打包的文件,都被转化为一个模块,比如import ./xxx/x.jpg或require(./xxx/x.js)
2023-06-03

详解利用Spring加载Properties配置文件

记得之前写Web项目的时候配置文件的读取都是用Properties这个类完成的,当时为了项目的代码的统一也就没做什么改动。但事后一直在琢磨SpringMVC会不会都配置的注解功能了?经过最近的研究返现SpringMVC确实带有这一项功能,S
2023-05-31

SpringSecurity使用LambdaDSL配置流程详解

SpringSecurity5.2对LambdaDSL语法的增强,允许使用lambda配置HttpSecurity、ServerHttpSecurity,重要提醒,之前的配置方法仍然有效。lambda的添加旨在提供更大的灵活性,但是用法是可选的。让我们看一下HttpSecurity的lambda配置与以前的配置样式相比
2023-02-15

Redis Sentinel服务配置流程(详解)

1、Redis Sentinel服务配置1.1简介 Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务: 监控(Monitoring): Sentinel 会不断地检查你的主
2022-06-04

SpringBoot配置文件加载方法详细讲解

springboot默认读取的配置文件名字是:“application.properties”和“application.yml”,默认读取四个位置的文件:根目录下、根目录的config目录下、classpath目录下、classpath目录里的config目录下
2022-11-13

Gateway集成Netty服务的配置加载详解

这篇文章主要为大家介绍了Gateway集成Netty服务的配置加载详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-28

SpringBoot加载读取配置文件过程详细分析

在实际的项目开发过程中,我们经常需要将某些变量从代码里面抽离出来,放在配置文件里面,以便更加统一、灵活的管理服务配置信息。所以本文将为大家总结一下SpringBoot加载配置文件的常用方式,需要的可以参考一下
2023-01-28

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录