Nacos 配置中心 Client 端源码分析

前言:

前面我们分析了 Ncaos 的注册中心性格源码,了解了 Nacos 注册中的服务注册、心跳检测、健康检查、集群间数据同步等源码,本篇开始我们分析一下 Nacos 配置中心的源码。

Nacos 系列文章传送门:

Nacos 初步认识和 Nacos 部署细节

Nacos 配置管理模型 – 命名空间(Namespace)、配置分组(Group)和配置集ID(Data ID)

Nacos 注册中心和配置中心【实战】

服务启动何时触发 Nacos 的注册流程?

Nacos Client 端服务注册流程源码分析

Nacos Server 端服务注册流程源码分析

Nacos 服务发现(订阅)源码分析(客户端)

Nacos 服务发现(订阅)源码分析(服务端)

Nacos Server 是如何通知 Nacos Client 服务下线?

Nacos Client 是如何接受 Nacos Server 推送的数据?

Nacos 故障转移源码分析(FailoverReactor)

Nacos 集群数据同步源码分析

SpringApplication#prepareContext 方法源码分析

SpringApplication#prepareContext 方法主要是做一些容器刷新之前的动作,完成各类初始化动作,其中有一个比较核心的操作,把启动类注入容器,为后续开启自动化配置奠定了基础,本篇我们重点关注 this.applyInitializers(context) 这行代码。

//org.springframework.boot.SpringApplication#prepareContext
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	//设置上下文环境
	context.setEnvironment(environment);
	//执行上下文后处理
	this.postProcessApplicationContext(context);
	//执行 ApplicationContextInitializer  本篇重点关注
	this.applyInitializers(context);
	//发布上下文准备好的监听事件
	listeners.contextPrepared(context);
	//关闭引导上下文
	bootstrapContext.close(context);
	if (this.logStartupInfo) {
		this.logStartupInfo(context.getParent() == null);
		this.logStartupProfileInfo(context);
	}
	//获取应用程序上下文的beanFactory 并设置一些属性
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	//注册单例bean springApplicationArguments  容器指定的参数封装成 bean  注入容器
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		//将 Banner 封装成 bean 注入到容器中
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	//是否是 DefaultListableBeanFactory 类型的容器
	if (beanFactory instanceof DefaultListableBeanFactory) {
		//是 强行覆盖
		((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	//是否懒加载
	if (this.lazyInitialization) {
		//加 懒加载 beanFactory 处理器
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	//获取启动类指定的参数
	Set<Object> sources = this.getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	//加载启动类 将启动类注入容器
	this.load(context, sources.toArray(new Object[0]));
	//发布容器加载完成事件
	listeners.contextLoaded(context);
}

SpringApplication#applyInitializers 方法源码分析

SpringApplication#applyInitializers 方法获取了所有的 ApplicationContextInitializer,调用 ApplicationContextInitializer 的 initialize 方法执行初始化。

//org.springframework.boot.SpringApplication#applyInitializers
protected void applyInitializers(ConfigurableApplicationContext context) {
	//迭代遍历 Initializers
	Iterator var2 = this.getInitializers().iterator();

	while(var2.hasNext()) {
		//Initializers 都实现了 ApplicationContextInitializer 接口  强转为 ApplicationContextInitializer 
		ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();
		//得到类型
		Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
		Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
		//initializer 执行初始化
		initializer.initialize(context);
	}

}

PropertySourceBootstrapConfiguration#initialize 方法源码分析

PropertySourceBootstrapConfiguration#initialize 方法真正实现了配置中心的加载,PropertySourceBootstrapConfiguration 类实现了 ApplicationContextInitializer 接口,PropertySourceBootstrapConfiguration 类在容器初始化的时候从配置中心拉取配置到本地,封装成 PropertySource 存入到 Environment 中提供给应用服务使用。

//org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration#initialize
public void initialize(ConfigurableApplicationContext applicationContext) {
	//属性来源
	List<PropertySource<?>> composite = new ArrayList();
	//propertySourceLocators 排序 propertySourceLocators 其实就是配置中心的相关信息
	AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
	boolean empty = true;
	//获取容器的环境配置环境信息
	ConfigurableEnvironment environment = applicationContext.getEnvironment();
	//迭代遍历配置
	Iterator var5 = this.propertySourceLocators.iterator();

	while(true) {
		Collection source;
		do {
			do {
				if (!var5.hasNext()) {
					if (!empty) {
						//可变属性
						MutablePropertySources propertySources = environment.getPropertySources();
						//日志配置
						String logConfig = environment.resolvePlaceholders("${logging.config:}");
						//读取环境
						LogFile logFile = LogFile.get(environment);
						//得带遍历属性配置
						Iterator var15 = environment.getPropertySources().iterator();

						while(var15.hasNext()) {
							PropertySource<?> p = (PropertySource)var15.next();
							//如果 bootstrapProperties 包含 就移出
							if (p.getName().startsWith("bootstrapProperties")) {
								propertySources.remove(p.getName());
							}
						}
						//插入属性来源
						this.insertPropertySources(propertySources, composite);
						//重新初始化日志系统
						this.reinitializeLoggingSystem(environment, logConfig, logFile);
						//设置日志级别
						this.setLogLevels(applicationContext, environment);
						//出来配置文件
						this.handleIncludedProfiles(environment);
					}

					return;
				}
				//属性来源定位器
				PropertySourceLocator locator = (PropertySourceLocator)var5.next();
				//调用 PropertySourceLocator#locateCollection 方法来读取配置 这里重点关注一下
				source = locator.locateCollection(environment);
			} while(source == null);
		} while(source.size() == 0);

		//属性list
		List<PropertySource<?>> sourceList = new ArrayList();
		//迭代遍历属性
		Iterator var9 = source.iterator();

		while(var9.hasNext()) {
			PropertySource<?> p = (PropertySource)var9.next();
			if (p instanceof EnumerablePropertySource) {
				EnumerablePropertySource<?> enumerable = (EnumerablePropertySource)p;
				sourceList.add(new BootstrapPropertySource(enumerable));
			} else {
				sourceList.add(new SimpleBootstrapPropertySource(p));
			}
		}

		logger.info("Located property source: " + sourceList);
		//加入属性集合
		composite.addAll(sourceList);
		empty = false;
	}
}

debugger 中 propertySourceLocators 信息:
在这里插入图片描述

debugger 中 PropertySource 信息:

在这里插入图片描述

PropertySourceLocator 类

我们知道了 PropertySourceBootstrapConfiguration 类在应用服务启动时候从配置中心拉取配置到本地供应用服务使用,这里只是加载拉取了配置中心的配置,而且我们知道配置来源自 propertySourceLocators 属性,propertySourceLocators 是 PropertySourceBootstrapConfiguration 类中自动注入的,源码如下:

@Autowired(
	required = false
)
private List<PropertySourceLocator> propertySourceLocators = new ArrayList();

propertySourceLocators 是个 List,从这里可以知道 Spring Cloud 应用是可以支持多配置中心的,从这里我们也可以知道 Spring Cloud 通过 PropertySourceBootstrapConfiguration 和 PropertySourceLocator 完成了配置配置中心配置的加载,那到底是如何加载 Nacos 配置中心的呢?

NacosConfigBootstrapConfiguration 类源码分析

跟踪 PropertySourceLocator 源码,发现 PropertySourceLocator 只是一个接口类,PropertySourceLocator 的唯一实现类是 NacosPropertySourceLocator 类,NacosPropertySourceLocator 肯定和 Nacos 配置中心的加载有着很大的关系,那 NacosPropertySourceLocator 何时被加载的?

package com.alibaba.cloud.nacos;

import com.alibaba.cloud.nacos.client.NacosPropertySourceLocator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnProperty(
    name = {"spring.cloud.nacos.config.enabled"},
    matchIfMissing = true
)
public class NacosConfigBootstrapConfiguration {
    public NacosConfigBootstrapConfiguration() {
    }

	//Nacos 配置信息
    @Bean
    @ConditionalOnMissingBean
    public NacosConfigProperties nacosConfigProperties() {
        return new NacosConfigProperties();
    }

	//创建 NacosConfigService 
    @Bean
    @ConditionalOnMissingBean
    public NacosConfigManager nacosConfigManager(NacosConfigProperties nacosConfigProperties) {
        return new NacosConfigManager(nacosConfigProperties);
    }

	//Nacos 配置中心的重点类
    @Bean
    public NacosPropertySourceLocator nacosPropertySourceLocator(NacosConfigManager nacosConfigManager) {
        return new NacosPropertySourceLocator(nacosConfigManager);
    }
}

可以看到 NacosPropertySourceLocator 是在 NacosConfigBootstrapConfiguration 类中被加载的,根据类名可以知道 NacosConfigBootstrapConfiguration 是个配置类,NacosConfigBootstrapConfiguration 是通过 Spring Boot 自动配置加载的,至此 NacosPropertySourceLocator 类的加载已经水落石出。

PropertySourceLocator 类源码分析

上面在分析 PropertySourceBootstrapConfiguration#initialize 方法时候,提到了 PropertySourceLocator#locateCollection 方法,该方法调用了 NacosPropertySourceLocator#locate 方法,Nacos 配置中心的加载逻辑就在该方法中。

public interface PropertySourceLocator {
    PropertySource<?> locate(Environment environment);

    default Collection<PropertySource<?>> locateCollection(Environment environment) {
        return locateCollection(this, environment);
    }

    static Collection<PropertySource<?>> locateCollection(PropertySourceLocator locator, Environment environment) {
		//调用 NacosPropertySourceLocator#locate 方法
        PropertySource<?> propertySource = locator.locate(environment);
		//propertySource 为空判断
        if (propertySource == null) {
            return Collections.emptyList();
        } else if (CompositePropertySource.class.isInstance(propertySource)) {
			//封装结果返回
            Collection<PropertySource<?>> sources = ((CompositePropertySource)propertySource).getPropertySources();
            List<PropertySource<?>> filteredSources = new ArrayList();
            Iterator var5 = sources.iterator();

            while(var5.hasNext()) {
                PropertySource<?> p = (PropertySource)var5.next();
                if (p != null) {
                    filteredSources.add(p);
                }
            }

            return filteredSources;
        } else {
            return Arrays.asList(propertySource);
        }
    }
}

NacosPropertySourceLocator#locate 方法源码解析

NacosPropertySourceLocator 实现了 PropertySourceLocator 接口,重写了 locate 方法,locate 方法会加载配置文件,将配置文件内容封装成 NacosPropertySource 返回,从源码中可以看出分别加载了共享配置、扩展配置、应用自身配置,我们分析加载应用自身配置这条链路,其实其他两条链路最终都调用了 NacosPropertySourceLocator#loadNacosDataIfPresent 方法。

//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#locate
public PropertySource<?> locate(Environment env) {
	//设置环境
	this.nacosConfigProperties.setEnvironment(env);
	//获取 ConfigService
	ConfigService configService = this.nacosConfigManager.getConfigService();
	//ConfigService 为空判断
	if (null == configService) {
		log.warn("no instance of config service found, can't load config from nacos");
		return null;
	} else {
		//超时时间
		long timeout = (long)this.nacosConfigProperties.getTimeout();
		//赋值 nacosPropertySourceBuilder
		this.nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService, timeout);
		//获取配置文件 name
		String name = this.nacosConfigProperties.getName();
		//获取前缀
		String dataIdPrefix = this.nacosConfigProperties.getPrefix();
		//前缀为空判断
		if (StringUtils.isEmpty(dataIdPrefix)) {
			//赋值
			dataIdPrefix = name;
		}
		//再次前缀为空判断
		if (StringUtils.isEmpty(dataIdPrefix)) {
			//默认使用 spring.application.name 的值
			dataIdPrefix = env.getProperty("spring.application.name");
		}
		//属性配置对象
		CompositePropertySource composite = new CompositePropertySource("NACOS");
		//加载共享配置
		this.loadSharedConfiguration(composite);
		//加载拓展配置
		this.loadExtConfiguration(composite);
		//加载应用配置
		this.loadApplicationConfiguration(composite, dataIdPrefix, this.nacosConfigProperties, env);
		return composite;
	}
}

NacosPropertySourceLocator#loadApplicationConfiguration 方法源码解析

NacosPropertySourceLocator#loadApplicationConfiguration 方法会获取应用的所有配置文件,循环调用 NacosPropertySourceLocator#loadNacosDataIfPresent 方法处理。

//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadApplicationConfiguration
private void loadApplicationConfiguration(CompositePropertySource compositePropertySource, String dataIdPrefix, NacosConfigProperties properties, Environment environment) {
	//配置文件扩展名
	String fileExtension = properties.getFileExtension();
	//配置组名
	String nacosGroup = properties.getGroup();
	//不带扩展名后缀查询 application
	this.loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup, fileExtension, true);
	//带扩展名后缀查询 application.yml
	this.loadNacosDataIfPresent(compositePropertySource, dataIdPrefix + "." + fileExtension, nacosGroup, fileExtension, true);
	//获取活跃的配置文件后缀 dev test prod
	String[] var7 = environment.getActiveProfiles();
	int var8 = var7.length;

	for(int var9 = 0; var9 < var8; ++var9) {
		//环境
		String profile = var7[var9];
		//dataId 确定配置文件使用
		String dataId = dataIdPrefix + "-" + profile + "." + fileExtension;
		//带环境 带扩展名后缀查询 application-dev.yml
		this.loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup, fileExtension, true);
	}

}

NacosPropertySourceLocator#loadNacosDataIfPresent 方法源码解析

NacosPropertySourceLocator#loadNacosDataIfPresent 方法对 dataId 和 group 进行简单判断之后会 NacosPropertySourceLocator#loadNacosPropertySource 方法加载配置中心。

//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) {
		if (null != group && group.trim().length() >= 1) {
			//经过 dataId group 判断后 开始加载配置中心
			NacosPropertySource propertySource = this.loadNacosPropertySource(dataId, group, fileExtension, isRefreshable);
			//读取的配置加入 propertySources
			//private final Set<PropertySource<?>> propertySources = new LinkedHashSet();
			this.addFirstPropertySource(composite, propertySource, false);
		}
	}
}

NacosPropertySourceLocator#loadNacosPropertySource 方法源码解析

NacosPropertySourceLocator#loadNacosPropertySource 方法进行简单判断之后调用 NacosPropertySourceBuilder#build 方法,因为 isRefreshable 为 true。

//com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadNacosPropertySource
private NacosPropertySource loadNacosPropertySource(final String dataId, final String group, String fileExtension, boolean isRefreshable) {
	//isRefreshable 为 true  
	//因此会执行 this.nacosPropertySourceBuilder.build(dataId, group, fileExtension, isRefreshable)
	return NacosContextRefresher.getRefreshCount() != 0L && !isRefreshable ? NacosPropertySourceRepository.getNacosPropertySource(dataId, group) : this.nacosPropertySourceBuilder.build(dataId, group, fileExtension, isRefreshable);
}

NacosPropertySourceBuilder#loadNacosData 方法源码解析

NacosPropertySourceBuilder#loadNacosData 方法会调用 NacosConfigService#getConfig 加载配置文件,并解析 Nacos 配置数据,封装成 NacosPropertySource 对象返回。

//com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder#build
NacosPropertySource build(String dataId, String group, String fileExtension, boolean isRefreshable) {
	//加载 Nacos 配置 重点关注
	List<PropertySource<?>> propertySources = this.loadNacosData(dataId, group, fileExtension);
	//创建 NacosPropertySource 对象
	NacosPropertySource nacosPropertySource = new NacosPropertySource(propertySources, group, dataId, new Date(), isRefreshable);
	//比较 NacosPropertySource 对象
	NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource);
	return nacosPropertySource;
}

NacosConfigService#getConfig 方法源码解析

NacosConfigService#getConfig 方法会调用 NacosConfigService#getConfigInner 方法加载配置文件,NacosConfigService#getConfigInner 方法会优先判断是否有故障转移情况,如果有会优先获取故障转移配置文件,直接返回,如果没有的话才会去服务端获取配置文件,如果在在获取服务端配置文件出现了异常,最后会获取快照配置文件返回。


//com.alibaba.nacos.client.config.NacosConfigService#getConfig
@Override
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {
	//调用 NacosConfigService#getConfigInner 方法加载配置中
	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);
	//dataId group 校验
	ParamUtils.checkKeyParam(dataId, group);
	//配置响应对象
	ConfigResponse cr = new ConfigResponse();
	//设置属性
	cr.setDataId(dataId);
	//设置租户 namespaceid
	cr.setTenant(tenant);
	cr.setGroup(group);
	
	// 优先使用本地配置
	//如果存在的故障转移的配置内容 且能读取到配置信息 则直接返回了 这样设计的目的是当 server 挂了  又需要修改配置 就可以读本地目录
	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);
		//数据加密处理
		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);
		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={}",
				agent.getName(), dataId, group, tenant, ioe.toString());
	}
	//获取快照数据
	content = LocalConfigInfoProcessor.getSnapshot(agent.getName(), dataId, group, tenant);
	LOGGER.warn("[{}] [get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}", agent.getName(),
			dataId, group, tenant, ContentUtils.truncateContent(content));
	cr.setContent(content);
	//数据加密处理
	String encryptedDataKey = LocalEncryptedDataKeyProcessor
			.getEncryptDataKeySnapshot(agent.getName(), dataId, group, tenant);
	cr.setEncryptedDataKey(encryptedDataKey);
	configFilterChainManager.doFilter(null, cr);
	content = cr.getContent();
	return content;
}

ClientWorker#getServerConfig 方法源码解析

ClientWorker#getServerConfig 方法是真正去 Nacos Server 拉取配置的方法,该方法的主要内容就是构造请求参数、请求头,发起 HTTP 调用(Nacos 1.X 使用的是 HTTP 方式,2.X 使用的是 grpc 的方法是),得到结果集后,对结果集进行处理返回。


//com.alibaba.nacos.client.config.impl.ClientWorker#getServerConfig
public ConfigResponse getServerConfig(String dataId, String group, String tenant, long readTimeout)
		throws NacosException {
	//配置响应对象
	ConfigResponse configResponse = new ConfigResponse();
	//group 如果为空 设置为 DEFAULT_GROUP
	if (StringUtils.isBlank(group)) {
		group = Constants.DEFAULT_GROUP;
	}

	//http 响应结果
	HttpRestResult<String> result = null;
	try {
		//http 请求入参封装(Nacos 1.x 版本使用 http 请求  2.X 版本使用 grpc 的方式)
		Map<String, String> params = new HashMap<String, String>(3);
		//租户为空判断 一般不为空
		if (StringUtils.isBlank(tenant)) {
			params.put("dataId", dataId);
			params.put("group", group);
		} else {
			params.put("dataId", dataId);
			params.put("group", group);
			params.put("tenant", tenant);
		}
		//发起 http 请求到 Nacos Server  url:/v1/cs/configs
		result = agent.httpGet(Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode(), readTimeout);
	} catch (Exception ex) {
		String message = String
				.format("[%s] [sub-server] get server config exception, dataId=%s, group=%s, tenant=%s",
						agent.getName(), dataId, group, tenant);
		LOGGER.error(message, ex);
		throw new NacosException(NacosException.SERVER_ERROR, ex);
	}
	//结果集处理
	switch (result.getCode()) {
		//成功
		case HttpURLConnection.HTTP_OK:
			//保存数据快照到本地
			LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, result.getData());
			//设置返回数据信息
			configResponse.setContent(result.getData());
			//配置类型
			String configType;
			//设置配置类型
			if (result.getHeader().getValue(CONFIG_TYPE) != null) {
				configType = result.getHeader().getValue(CONFIG_TYPE);
			} else {
				configType = ConfigType.TEXT.getType();
			}
			configResponse.setConfigType(configType);
			//数据加密key
			String encryptedDataKey = result.getHeader().getValue(ENCRYPTED_DATA_KEY);
			//数据加密
			LocalEncryptedDataKeyProcessor
					.saveEncryptDataKeySnapshot(agent.getName(), dataId, group, tenant, encryptedDataKey);
			configResponse.setEncryptedDataKey(encryptedDataKey);
			return configResponse;
		case HttpURLConnection.HTTP_NOT_FOUND:
			//没有找到接口 会删除本地配置快照文件
			LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, null);
			//也是删除
			LocalEncryptedDataKeyProcessor.saveEncryptDataKeySnapshot(agent.getName(), dataId, group, tenant, null);
			//返回
			return configResponse;
		case HttpURLConnection.HTTP_CONFLICT: {
			//冲突 配置正在修改
			LOGGER.error(
					"[{}] [sub-server-error] get server config being modified concurrently, dataId={}, group={}, "
							+ "tenant={}", agent.getName(), dataId, group, tenant);
			throw new NacosException(NacosException.CONFLICT,
					"data being modified, dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
		}
		case HttpURLConnection.HTTP_FORBIDDEN: {
			//无权限
			LOGGER.error("[{}] [sub-server-error] no right, dataId={}, group={}, tenant={}", agent.getName(),
					dataId, group, tenant);
			throw new NacosException(result.getCode(), result.getMessage());
		}
		default: {
			//默认的处理 抛出异常
			LOGGER.error("[{}] [sub-server-error]  dataId={}, group={}, tenant={}, code={}", agent.getName(),
					dataId, group, tenant, result.getCode());
			throw new NacosException(result.getCode(),
					"http error, code=" + result.getCode() + ",dataId=" + dataId + ",group=" + group + ",tenant="
							+ tenant);
		}
	}
}

至此 Nacos Client 拉取配置中心配置的流程分析完毕,我们知道了配置中心的加载是在应用启动且容器刷新之前加载的,加载的整个流程还是比较简单的,最终会把加载到的配置加入到环境变量中,希望本篇的分析可以帮助到有需要的朋友。

欢迎提出建议及对错误的地方指出纠正。

相关推荐

  1. Nacos 服务发现(订阅)分析(客户

    2024-07-22 13:08:02       17 阅读
  2. 分布式微服务 - 4.配置中心 - 2.Nacos

    2024-07-22 13:08:02       32 阅读
  3. Nacos-client 2.x 使用nginx配置

    2024-07-22 13:08:02       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-22 13:08:02       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-22 13:08:02       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-22 13:08:02       45 阅读
  4. Python语言-面向对象

    2024-07-22 13:08:02       55 阅读

热门阅读

  1. OpenStack中nova的架构

    2024-07-22 13:08:02       14 阅读
  2. MCU常见相关术语缩写说明

    2024-07-22 13:08:02       13 阅读
  3. 【Statement对象】

    2024-07-22 13:08:02       18 阅读
  4. 基于深度学习的商品推荐

    2024-07-22 13:08:02       18 阅读
  5. 鸿蒙笔记--动画

    2024-07-22 13:08:02       18 阅读