跳至主要內容

Nacos配置中心

向往大约 2 分钟源码分析《Nacos》源码分析

配置获取实现

以Spring Cloud应用为例,分析一下应用启动时如何获取Nacos上面的配置。

核心类:NacosPropertySourceLocator,该类继承了PropertySourceLocatorPropertySourceLocator是Spring Cloud提供的接口,该接口的作用是让用户可定制化的将一些配置加载到 Environment。这部分配置获取遵循了 Spring Cloud Config 的理念,即希望能从外部储存获取。

在服务启动准备上下文阶段会调用PropertySourceBootstrapConfiguration#initialize方法,该方法会根据order排序执行所有PropertySourceLocator实例的locate方法。NacosPropertySourceLocator#locate 会获取server端配置,核心代码如下:

@Override
public PropertySource<?> locate(Environment env) {
   nacosConfigProperties.setEnvironment(env);
   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 = new NacosPropertySourceBuilder(configService,
         timeout);
   String name = nacosConfigProperties.getName();

   String dataIdPrefix = nacosConfigProperties.getPrefix();
   if (StringUtils.isEmpty(dataIdPrefix)) {
      dataIdPrefix = name;
   }

   if (StringUtils.isEmpty(dataIdPrefix)) {
      dataIdPrefix = env.getProperty("spring.application.name");
   }
   //获取配置返回,后面加载到Environment中
   CompositePropertySource composite = new CompositePropertySource(
         NACOS_PROPERTY_SOURCE_NAME);
   // 加载共享配置
   loadSharedConfiguration(composite);
   //加载扩展配置
   loadExtConfiguration(composite);
   //加载应用配置
   loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
  
   return composite;
}

调用链如下:

image-20221123103042262

上述加载配置会调用com.alibaba.nacos.api.config.ConfigService#getConfig方法去获取配置,核心逻辑在com.alibaba.nacos.client.config.NacosConfigService#getConfigInner 方法中,

private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {
    group = null2defaultGroup(group);
    ParamUtils.checkKeyParam(dataId, group);
    ConfigResponse cr = new ConfigResponse();
    
    cr.setDataId(dataId);
    cr.setTenant(tenant);
    cr.setGroup(group);
    
    // 优先使用本地配置,我本地配置文件在C:\Users\Administrator\nacos\config\fixed-nacos.cmp_8848-dev_nacos\snapshot-tenant目录
    String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);
    if (content != null) {
        LOGGER.warn("[{}] [get-config] get failover ok, dataId={}, group={}, tenant={}, config={}", agent.getName(),
                dataId, group, tenant, ContentUtils.truncateContent(content));
        cr.setContent(content);
        configFilterChainManager.doFilter(null, cr);
        content = cr.getContent();
        return content;
    }
    // 如果本地不存在配置文件,从服务端获取配置文件
    try {
        String[] ct = worker.getServerConfig(dataId, group, tenant, timeoutMs);
        cr.setContent(ct[0]);
        
        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={}",
                agent.getName(), dataId, group, tenant, ioe.toString());
    }
    
    LOGGER.warn("[{}] [get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}", agent.getName(),
            dataId, group, tenant, ContentUtils.truncateContent(content));
    content = LocalConfigInfoProcessor.getSnapshot(agent.getName(), dataId, group, tenant);
    cr.setContent(content);
    configFilterChainManager.doFilter(null, cr);
    content = cr.getContent();
    return content;
}

配置刷新实现

配置刷新是通过事件监听实现的,com.alibaba.cloud.nacos.refresh.NacosContextRefresher监听了ApplicationReadyEvent事件,ApplicationReadyEvent在服务准备好提供请求后发布。