SpringBoot启动时,初始化完成运行环境信息准备之后,会调用SpringApplication.prepareContext方法开始准备上下文,在prepareContext方法中会通过applyInitializers方法调用所有实现了ApplicationContextInitializer类的实例。
protected void applyInitializers(ConfigurableApplicationContext context) {
//获取所有实现了ApplicationContextInitializer的类,主要看PropertySourceBootstrapConfiguration
Iterator var2 = this.getInitializers().iterator();
while(var2.hasNext()) {
ApplicationContextInitializer initializer = (ApplicationContextInitializer)var2.next();
Class requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
PropertySourceBootstrapConfiguration.initialize方法
public void initialize(ConfigurableApplicationContext applicationContext) {
List<PropertySource<?>> composite = new ArrayList<>();
//对propertySourceLocators数组进行排序
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);//将source添加到数组
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());
}
}
//将远程的配置文件加载到propertySources的头部
insertPropertySources(propertySources, composite);
reinitializeLoggingSystem(environment, logConfig, logFile);
setLogLevels(applicationContext, environment);
handleIncludedProfiles(environment);
}
}
PropertySourceLocator.locateCollection方法
static default Collection<PropertySource<?>> locateCollection(PropertySourceLocator locator, Environment environment) {
//调用PropertySourceLocator实现类的locate方法,主要看NacosPropertySourceLocator.locate
PropertySource propertySource = locator.locate(environment);
if(propertySource == null) {
return Collections.emptyList();
} else if(CompositePropertySource.class.isInstance(propertySource)) {
Collection sources = ((CompositePropertySource)propertySource).getPropertySources();
ArrayList 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(new PropertySource[]{propertySource});
}
}
NacosPropertySourceLocator.locate
public PropertySource<?> locate(Environment env) {
this.nacosConfigProperties.setEnvironment(env);
ConfigService configService = this.nacosConfigManager.getConfigService();
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();
this.nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService, timeout);
String name = this.nacosConfigProperties.getName();
String dataIdPrefix = this.nacosConfigProperties.getPrefix();
if(StringUtils.isEmpty(dataIdPrefix)) {
dataIdPrefix = name;
}
if(StringUtils.isEmpty(dataIdPrefix)) {
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.loadSharedConfiguration加载共享配置,通过在bootstrap.properties中的spring.cloud.nacos.config.shared-configs进行配置,设置dataId,group等属性如果想要此配置支持自动刷新,需要设置refresh属性为true,默认为false,不支持自动刷新。
private void loadSharedConfiguration(CompositePropertySource compositePropertySource) {
//获取bootstrap.properties中spring.cloud.nacos.config.sharedConfigs的配置
List sharedConfigs = this.nacosConfigProperties.getSharedConfigs();
if(!CollectionUtils.isEmpty(sharedConfigs)) {
//检查配置文件类型是否支持
this.checkConfiguration(sharedConfigs, "shared-configs");
//加载配置文件
this.loadNacosConfiguration(compositePropertySource, sharedConfigs);
}
}
NacosPropertySourceLocator.checkConfiguration检查配置文件的类型是否支持,默认支持properties类型的配置文件类型,可以通过spring.cloud.nacos.config.file-extension设置
private void checkConfiguration(List<Config> configs, String tips) {
String[] dataIds = new String[configs.size()];
for(int i = 0; i < configs.size(); ++i) {
String dataId = ((Config)configs.get(i)).getDataId();
if(dataId == null || dataId.trim().length() == 0) {
throw new IllegalStateException(String.format("the [ spring.cloud.nacos.config.%s[%s] ] must give a dataId", new Object[]{tips, Integer.valueOf(i)}));
}
dataIds[i] = dataId;
}
//检查dataId的文件类型Nacos是否支持,默认支持properties,可以通过spring.cloud.nacos.config.file-extension
//配置增加xml,yml,yaml,json等类型文件
NacosDataParserHandler.getInstance().checkDataId(dataIds);
}
NacosPropertySourceLocator.loadNacosConfiguration
private void loadNacosConfiguration(CompositePropertySource composite, List<Config> configs) {
Iterator var3 = configs.iterator();
while(var3.hasNext()) {
Config config = (Config)var3.next();
String dataId = config.getDataId();
//截取配置文件类型
String fileExtension = dataId.substring(dataId.lastIndexOf(".") + 1);
//加载配置文件
this.loadNacosDataIfPresent(composite, dataId, config.getGroup(), fileExtension, config.isRefresh());
}
}
NacosPropertySourceLocator.loadNacosDataIfPresent
private void loadNacosDataIfPresent(CompositePropertySource composite, String dataId, String group, String fileExtension, boolean isRefreshable) {
if(null != dataId && dataId.trim().length() >= 1) {
if(null != group && group.trim().length() >= 1) {
//加载配置文件
NacosPropertySource propertySource = this.loadNacosPropertySource(dataId, group, fileExtension, isRefreshable);
//将新加载的配置文件放到composite的头部
this.addFirstPropertySource(composite, propertySource, false);
}
}
}
NacosPropertySourceLocator.loadNacosPropertySource,如果isRefreshable为false,即不支持自动刷新配置文件,从缓存中加载配置文件,isRefreshable为true,从远程加载配置文件
private NacosPropertySource loadNacosPropertySource(String dataId, String group, String fileExtension, boolean isRefreshable) {
return NacosContextRefresher.getRefreshCount() != 0L && !isRefreshable?
NacosPropertySourceRepository.getNacosPropertySource(dataId, group):
this.nacosPropertySourceBuilder.build(dataId, group, fileExtension, isRefreshable);
}
NacosPropertySourceBuilder.build从远端加载配置文件
NacosPropertySource build(String dataId, String group, String fileExtension, boolean isRefreshable) {
//加载远端的配置文件
Map p = this.loadNacosData(dataId, group, fileExtension);
//将Map格式的配置转换为NacosPropertySource
NacosPropertySource nacosPropertySource = new NacosPropertySource(group, dataId, p, new Date(), isRefreshable);
//将配置保存到Map缓存中
NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource);
return nacosPropertySource;
}
NacosPropertySourceBuilder.loadNacosData调用通过ConfigService实例调用Nacos远端获取配置文件,ConfigService实例的获取是从NacosConfigManager获取的。NacosConfigManager的实例化通过
NacosConfigAutoConfiguration.nacosConfigManager来完成。
private Map<String, Object> loadNacosData(String dataId, String group, String fileExtension) {
String data = null;
try {
data = this.configService.getConfig(dataId, group, this.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", new Object[]{dataId, group, data}));
}
Map e = NacosDataParserHandler.getInstance().parseNacosData(data, fileExtension);
return e == null?EMPTY_MAP:e;
} catch (NacosException var6) {
log.error("get data from Nacos error,dataId:{}, ", dataId, var6);
} catch (Exception var7) {
log.error("parse data from Nacos error,dataId:{},data:{},", new Object[]{dataId, data, var7});
}
return EMPTY_MAP;
}
@Bean
public NacosConfigManager nacosConfigManager(NacosConfigProperties nacosConfigProperties) {
return new NacosConfigManager(nacosConfigProperties);
}
NacosPropertySourceLocator.loadExtConfiguration加载拓展配置,通过在bootstrap.properties中的spring.cloud.nacos.config.extension-configs进行配置,设置dataId,group等属性如果想要此配置支持自动刷新,需要设置refresh属性为true,默认为false,不支持自动刷新。
private void loadExtConfiguration(CompositePropertySource compositePropertySource) {
List extConfigs = this.nacosConfigProperties.getExtensionConfigs();
if(!CollectionUtils.isEmpty(extConfigs)) {
this.checkConfiguration(extConfigs, "extension-configs");
this.loadNacosConfiguration(compositePropertySource, extConfigs);
}
}
NacosPropertySourceBuilder.loadApplicationConfiguration加载自身的配置,根据spring.cloud.nacos.config.prefix(默认等于spring.application.name)配置获得配置的文件名称
private void loadApplicationConfiguration(CompositePropertySource compositePropertySource, String dataIdPrefix, NacosConfigProperties properties, Environment environment) {
String fileExtension = properties.getFileExtension();
String nacosGroup = properties.getGroup();
this.loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup, fileExtension, true);
this.loadNacosDataIfPresent(compositePropertySource, dataIdPrefix + "." + fileExtension, nacosGroup, fileExtension, true);
String[] var7 = environment.getActiveProfiles();
int var8 = var7.length;
for(int var9 = 0; var9 < var8; ++var9) {//循环加载激活的配置
String profile = var7[var9];
String dataId = dataIdPrefix + "-" + profile + "." + fileExtension;
this.loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup, fileExtension, true);
}
}