赞
踩
spring-cloud-alibaba客户端版本:2.2.1.RELEASE
nacos服务端版本:2.0.4
通过springboot spi机制加载spring.factories文件配置的类
NacosConfigBootstrapConfiguration,PropertySourceBootstrapConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.NacosConfigBootstrapConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.NacosConfigAutoConfiguration,\
com.alibaba.cloud.nacos.endpoint.NacosConfigEndpointAutoConfiguration
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.alibaba.cloud.nacos.diagnostics.analyzer.NacosConnectionFailureAnalyzer
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); } //加载nacos配置的 @Bean public NacosPropertySourceLocator nacosPropertySourceLocator( NacosConfigManager nacosConfigManager) { return new NacosPropertySourceLocator(nacosConfigManager); } }
# AutoConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\ org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration,\ org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\ org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,\ org.springframework.cloud.autoconfigure.WritableEnvironmentEndpointAutoConfiguration # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.cloud.bootstrap.BootstrapApplicationListener,\ org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,\ org.springframework.cloud.context.restart.RestartListener # Bootstrap components org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,\ org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration,\ org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\ org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
PropertySourceBootstrapConfiguration 实现了springboot初始化器 当spring ioc启动就会调用 initialize方法
@Override public void initialize(ConfigurableApplicationContext applicationContext) { List<PropertySource<?>> composite = new ArrayList<>(); AnnotationAwareOrderComparator.sort(this.propertySourceLocators); boolean empty = true; ConfigurableEnvironment environment = applicationContext.getEnvironment(); for (PropertySourceLocator locator : this.propertySourceLocators) { //回调所有实现PropertySourceLocator接口实例的locate方法, Collection<PropertySource<?>> source = locator.locateCollection(environment); if (source == null || source.size() == 0) { continue; } List<PropertySource<?>> sourceList = new ArrayList<>(); for (PropertySource<?> p : source) { sourceList.add(new BootstrapPropertySource<>(p)); } logger.info("Located property source: " + sourceList); composite.addAll(sourceList); empty = false; } if (!empty) { MutablePropertySources propertySources = environment.getPropertySources(); String logConfig = environment.resolvePlaceholders("${logging.config:}"); LogFile logFile = LogFile.get(environment); for (PropertySource<?> p : environment.getPropertySources()) { if (p.getName().startsWith(BOOTSTRAP_PROPERTY_SOURCE_NAME)) { propertySources.remove(p.getName()); } } insertPropertySources(propertySources, composite); reinitializeLoggingSystem(environment, logConfig, logFile); setLogLevels(applicationContext, environment); handleIncludedProfiles(environment); } }
PropertySourceLoader.locateCollection
这个方法会调用子类的locate方法,来获得一个PropertySource,然后将PropertySource集合返回。接
着它会调用 ConfigServicePropertySourceLocator 的locate方法。
static Collection<PropertySource<?>> locateCollection(PropertySourceLocator locator, Environment environment) { PropertySource<?> propertySource = locator.locate(environment); if (propertySource == null) { return Collections.emptyList(); } if (CompositePropertySource.class.isInstance(propertySource)) { Collection<PropertySource<?>> sources = ((CompositePropertySource) propertySource) .getPropertySources(); List<PropertySource<?>> filteredSources = new ArrayList<>(); for (PropertySource<?> p : sources) { if (p != null) { filteredSources.add(p); } } return filteredSources; } else { return Arrays.asList(propertySource); } }
NacosPropertySourceLocator.locate
这个就是Nacos 配置中心加载的的关键实现了,分别调用三个方法来加载配置
NAOCOS配置加载顺序:共享配置 --> 扩展配置 --> 自身配置(后面优先级高)
@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"); } CompositePropertySource composite = new CompositePropertySource( NACOS_PROPERTY_SOURCE_NAME); //加载共享配置 loadSharedConfiguration(composite); //加载扩展配置 loadExtConfiguration(composite); //加载自身配置 loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env); return composite; }
loadApplicationConfiguration()
我们可以先不管加载共享配置、扩展配置的方法,最终本质上都是去远程服务上读取配置,只是传入的
参数不一样。
private void loadApplicationConfiguration( CompositePropertySource compositePropertySource, String dataIdPrefix, NacosConfigProperties properties, Environment environment) { String fileExtension = properties.getFileExtension(); String nacosGroup = properties.getGroup(); // load directly once by default 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; loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup, fileExtension, true); } }
loadNacosDataIfPresent()
调用 loadNacosPropertySource 加载存在的配置信息。
把加载之后的配置属性保存到CompositePropertySource中。
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 propertySource = this.loadNacosPropertySource(dataId, group,
fileExtension, isRefreshable);
this.addFirstPropertySource(composite, propertySource, false);
}
loadNacosPropertySource()
private NacosPropertySource loadNacosPropertySource(final String dataId,
final String group, String fileExtension, boolean isRefreshable) {
if (NacosContextRefresher.getRefreshCount() != 0) {
//是否支持自动刷新,// 如果不支持自动刷新配置则自动从缓存获
取返回 if (!isRefreshable) {
return NacosPropertySourceRepository.getNacosPropertySource(dataId,
group);
}
}
//构造器从配置中心获取数据
return nacosPropertySourceBuilder.build(dataId, group, fileExtension,
isRefreshable);
}
nacosPropertySourceBuilder.build()
NacosPropertySource build(String dataId, String group, String fileExtension,
boolean isRefreshable) {
//调用loadNacosData加载远程数据
Map<String, Object> p = loadNacosData(dataId, group, fileExtension);
NacosPropertySource nacosPropertySource = new NacosPropertySource(group, dataId,
p, new Date(), isRefreshable);
//返回Nacos属性源
NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource);
return nacosPropertySource;
}
loadNacosData()
加载Nacos的数据。
private Map<String, Object> loadNacosData(String dataId, String group, String fileExtension) { String data = null; try { // http远程访问配置中心,获取配置数据 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 EMPTY_MAP; } if (log.isDebugEnabled()) { log.debug(String.format( "Loading nacos data, dataId: '%s', group: '%s', data: %s", dataId, group, data)); } //根据扩展名进行数据的解析 Map<String, Object> dataMap = NacosDataParserHandler.getInstance() .parseNacosData(data, fileExtension); return dataMap == null ? EMPTY_MAP : dataMap; } 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 EMPTY_MAP; }
getConfigInner()
private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException { group = this.null2defaultGroup(group); ParamUtils.checkKeyParam(dataId, group); ConfigResponse cr = new ConfigResponse(); cr.setDataId(dataId); cr.setTenant(tenant); cr.setGroup(group); // 优先使用本地配置 String content = LocalConfigInfoProcessor.getFailover(this.agent.getName(), dataId, group, tenant); if (content != null) { LOGGER.warn("[{}] [get-config] get failover ok, dataId={}, group={}, tenant={}, config={}", new Object[]{this.agent.getName(), dataId, group, tenant, ContentUtils.truncateContent(content)}); cr.setContent(content); this.configFilterChainManager.doFilter((IConfigRequest)null, cr); content = cr.getContent(); return content; } else { try { String[] ct = this.worker.getServerConfig(dataId, group, tenant, timeoutMs); cr.setContent(ct[0]); this.configFilterChainManager.doFilter((IConfigRequest)null, cr); content = cr.getContent(); return content; } catch (NacosException var9) { if (403 == var9.getErrCode()) { throw var9; } else { LOGGER.warn("[{}] [get-config] get from server error, dataId={}, group={}, tenant={}, msg={}", new Object[]{this.agent.getName(), dataId, group, tenant, var9.toString()}); LOGGER.warn("[{}] [get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}", new Object[]{this.agent.getName(), dataId, group, tenant, ContentUtils.truncateContent(content)}); content = LocalConfigInfoProcessor.getSnapshot(this.agent.getName(), dataId, group, tenant); cr.setContent(content); this.configFilterChainManager.doFilter((IConfigRequest)null, cr); content = cr.getContent(); return content; } } } }
clientWorker.getServerConfig()
通过agent.httpGet发起http请求,获取远程服务的配置。
public String[] getServerConfig(String dataId, String group, String tenant, long readTimeout) throws NacosException { String[] ct = new String[2]; if (StringUtils.isBlank(group)) { group = "DEFAULT_GROUP"; } HttpSimpleClient.HttpResult result = null; try { List<String> params = null; if (StringUtils.isBlank(tenant)) { params = new ArrayList(Arrays.asList("dataId", dataId, "group", group)); } else { params = new ArrayList(Arrays.asList("dataId", dataId, "group", group, "tenant", tenant)); } result = this.agent.httpGet("/v1/cs/configs", (List)null, params, this.agent.getEncode(), readTimeout); } catch (IOException var10) { String message = String.format("[%s] [sub-server] get server config exception, dataId=%s, group=%s, tenant=%s", this.agent.getName(), dataId, group, tenant); LOGGER.error(message, var10); throw new NacosException(500, var10); } switch (result.code) { case 200: LocalConfigInfoProcessor.saveSnapshot(this.agent.getName(), dataId, group, tenant, result.content); ct[0] = result.content; if (result.headers.containsKey("Config-Type")) { ct[1] = (String)((List)result.headers.get("Config-Type")).get(0); } else { ct[1] = ConfigType.TEXT.getType(); } return ct; case 403: LOGGER.error("[{}] [sub-server-error] no right, dataId={}, group={}, tenant={}", new Object[]{this.agent.getName(), dataId, group, tenant}); throw new NacosException(result.code, result.content); case 404: LocalConfigInfoProcessor.saveSnapshot(this.agent.getName(), dataId, group, tenant, (String)null); return ct; case 409: LOGGER.error("[{}] [sub-server-error] get server config being modified concurrently, dataId={}, group={}, tenant={}", new Object[]{this.agent.getName(), dataId, group, tenant}); throw new NacosException(409, "data being modified, dataId=" + dataId + ",group=" + group + ",tenant=" + tenant); default: LOGGER.error("[{}] [sub-server-error] dataId={}, group={}, tenant={}, code={}", new Object[]{this.agent.getName(), dataId, group, tenant, result.code}); throw new NacosException(result.code, "http error, code=" + result.code + ",dataId=" + dataId + ",group=" + group + ",tenant=" + tenant); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。