Spring Cloud Alibaba Nacos Config加载配置详解流程

目录
  • 1、加载节点
  • 2、NacosPropertySourceLocator的注册
  • 3、加载
    • 3.1、加载share
    • 3.2、加载extention
    • 3.3、加载主配置文件

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 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring Cloud Alibaba Nacos Config配置中心实现

    什么是 Nacos Config 在分布式系统中,由于服务数量巨多,为了方便服务 配置文件统一管理,实时更新,所以需要分布式配置中心组件. Spring Cloud Alibaba Nacos Config 是 Spring Cloud Config 的替代方案. Nacos Config 的存储配置功能为分布式系统中的外部化配置提供服务器端和客户端支持,可以在 Nacos 中集中管理 Spring Cloud 应用的外部属性配置. 引入依赖 在 pom.xml 中添加 spring-cloud

  • Spring Cloud Alibaba Nacos Config进阶使用

    目录 一.SpringBoot 使用 Nacos Config 实现多环境切换 1. 现象 2. 引入依赖 3. 添加bootstrap.yaml配置文件 4. 配置对应关系图 5. 文件格式简述 6. 启动nacos 8. 添加测试controller 9. 启动Springboot工程并观察到如下日志则为成功 10. 浏览器验证 11. 调整激活环境 12. 新建test环境配置 13. test配置关系图 14. 测试方法 15. 重启springboot服务,监控控制台输出 16. 浏览

  • Spring Cloud Alibaba Nacos Config加载配置详解流程

    目录 1.加载节点 2.NacosPropertySourceLocator的注册 3.加载 3.1.加载share 3.2.加载extention 3.3.加载主配置文件 1.加载节点 SpringBoot启动时,会执行这个方法:SpringApplication#run,这个方法中会调prepareContext来准备上下文,这个方法中调用了applyInitializers方法来执行实现了ApplicationContextInitializer接口的类的initialize方法.其中包括

  • spring cloud alibaba Nacos 注册中心搭建过程详解

    这篇文章主要介绍了spring cloud alibaba Nacos 注册中心搭建过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 nacos下载地址 什么是 Nacos? nacos主要起到俩个作用一个是注册中心,另外一个是配置中心. 下面图 是nacos的功能结构图 运行环境 JDK 1.8+: Maven 3.2.x+: 下载 你可以通过源码和发行包两种方式来获取 Nacos. nacos发行包下载地址 选择版本解压 unzip

  • Spring cloud alibaba之Gateway网关功能特征详解

    目录 1.网关简介 2.什么是spring cloud gateway 2.1核心概念 3.Spring Cloud Gateway快速开始 5.路由断言工厂(Route Predicate Factories)配置 6.自定义路由断言工厂 7.Filter过滤器 8.自定义过滤器 9.自定义全局过滤器(Global Filters) 10.Gateway跨域配置(CORS Configuration) 11.Gateway整合Sentinel进行流控 12.流控配置说明 13.自定义重写流控返

  • SpringBoot使用Shiro实现动态加载权限详解流程

    目录 一.序章 二.SpringBoot集成Shiro 1.引入相关maven依赖 2.自定义Realm 3.Shiro配置类 三.shiro动态加载权限处理方法 四.shiro中自定义角色与权限过滤器 1.自定义uri权限过滤器 zqPerms 2.自定义角色权限过滤器 zqRoles 3.自定义token过滤器 五.项目中会用到的一些工具类常量等 1.Shiro工具类 2.Redis常量类 3.Spring上下文工具类 六.案例demo源码 一.序章 基本环境 spring-boot 2.1

  • ionic2懒加载配置详解

    文章标题为part 1,并解释目前可以如此配置,但后续使用上可能还有变动. 以ion-cli默认home组件为例.添加home.module.ts文件 import { NgModule } from '@angular/core'; import { IonicPageModule } from 'ionic-angular'; import { HomePage } from './home'; @NgModule({ declarations: [HomePage], imports: [

  • Spring Cloud集成Nacos Config动态刷新源码剖析

    目录 正文 Nacos Config动态刷新机制 Nacos Config 长轮询源码剖析 ClientWorker构造器初始化线程池 长轮询流程方法 正文 从远端服务器获取变更数据的主要模式有两种:推(push)和拉(pull).Push 模式简单来说就是服务端主动将数据变更信息推送给客户端,这种模式优点是时效性好,服务端数据发生变更可以立马通知到客户端,但这种模式需要服务端维持与客户端的心跳连接,会增加服务端实现的复杂度,服务端也需要占用更多的资源来维持与客户端的连接. 而 Pull 模式则

  • Spring Cloud Alibaba Nacos两种检查机制

    目录 两种健康检查机制 如何设置健康检查机制? 客户端主动上报机制 服务端反向探测机制 TCP 探测 HTTP 探测 集群下的健康检查机制 总结 前言: Spring Cloud Alibaba Nacos 作为注册中心不止提供了服务注册和服务发现功能,它还提供了服务可用性监测的机制.有了此机制之后,Nacos 才能感知服务的健康状态,从而为服务调用者提供健康的服务实例,最终保证了业务系统能够正常的执行. 两种健康检查机制 Nacos 中提供了两种健康检查机制: 客户端主动上报机制. 服务器端反

  • Spring Cloud Alibaba Nacos服务治理平台,服务注册、RestTemplate实现微服务之间访问负载均衡访问的问题

    目录 Nacos简介 ☘Spring Cloud 组件依赖版本 ☘Nacos部署 ☘访问Nacos平台 Nacos服务注册.微服务访问.负载均衡实现 nacos-consumer微服务创建 ☘nacos-provider微服务创建 测试 Nacos简介 Github:https://github.com/alibaba/nacos官网文档:https://nacos.io/zh-cn/docs/what-is-nacos.htmlNacos 提供了发现.配置和管理微服务能力,能快速实现动态服务发

随机推荐