1、问题拆解
(1)springBoot默认会去哪里找应用的配置文件?
(2)配置文件的名称是什么?
(3)配置文件的后缀是什么?
(4)采用哪种方式加载进来?
(5)内容解析?
2、拉取栈帧
getInputStream:182, ClassPathResource (org.springframework.core.io)
process:199, YamlProcessor (org.springframework.beans.factory.config)
process:164, YamlProcessor (org.springframework.beans.factory.config)
load:76, OriginTrackedYamlLoader (org.springframework.boot.env)
load:50, YamlPropertySourceLoader (org.springframework.boot.env)
loadDocuments:607, ConfigFileApplicationListener$Loader (org.springframework.boot.context.config)
/**
m6、加载文件
**/
load:523, ConfigFileApplicationListener$Loader (org.springframework.boot.context.config)
loadForFileExtension:498, ConfigFileApplicationListener$Loader (org.springframework.boot.context.config)
/**
m5、处理配置文件的后缀
**/
load:468, ConfigFileApplicationListener$Loader (org.springframework.boot.context.config)
lambda$null$7:447, ConfigFileApplicationListener$Loader (org.springframework.boot.context.config)
accept:-1, 1430199669 (org.springframework.boot.context.config.ConfigFileApplicationListener$Loader$$Lambda$118)
forEach:75, Iterable (java.lang)
lambda$load$8:447, ConfigFileApplicationListener$Loader (org.springframework.boot.context.config)
accept:-1, 1213871206 (org.springframework.boot.context.config.ConfigFileApplicationListener$Loader$$Lambda$115)
forEach:75, Iterable (java.lang)
/**
m4、处理配置文件的路径和名称
**/
load:444, ConfigFileApplicationListener$Loader (org.springframework.boot.context.config)
lambda$load$0:347, ConfigFileApplicationListener$Loader (org.springframework.boot.context.config)
accept:-1, 1100109058 (org.springframework.boot.context.config.ConfigFileApplicationListener$Loader$$Lambda$99)
apply:54, FilteredPropertySource (org.springframework.boot.context.config)
/**
m3、委托给内部类Loader
**/
load:335, ConfigFileApplicationListener$Loader (org.springframework.boot.context.config)
addPropertySources:226, ConfigFileApplicationListener (org.springframework.boot.context.config)
/**
m2、ConfigFileApplicationListener也是一个EnvironmentPostProcessor,
**/
postProcessEnvironment:210, ConfigFileApplicationListener (org.springframework.boot.context.config)
onApplicationEnvironmentPreparedEvent:200, ConfigFileApplicationListener (org.springframework.boot.context.config)
/**
m1、ConfigFileApplicationListener是一个ApplicationListener,
**/
onApplicationEvent:188, ConfigFileApplicationListener (org.springframework.boot.context.config)
doInvokeListener:172, SimpleApplicationEventMulticaster (org.springframework.context.event)
invokeListener:165, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:139, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:127, SimpleApplicationEventMulticaster (org.springframework.context.event)
environmentPrepared:80, EventPublishingRunListener (org.springframework.boot.context.event)
environmentPrepared:53, SpringApplicationRunListeners (org.springframework.boot)
prepareEnvironment:345, SpringApplication (org.springframework.boot)
run:308, SpringApplication (org.springframework.boot)
run:1237, SpringApplication (org.springframework.boot)
run:1226, SpringApplication (org.springframework.boot)
main:62, GfundActbApiApplication (com.gome.gfund.actb)
3、问题解析
m1和m2是springBoot启动时的固有流程,我们从m3处开始看:
// m3:org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load()
void load() {
FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
(defaultProperties) -> {
this.profiles = new LinkedList<>();
this.processedProfiles = new LinkedList<>();
this.activatedProfiles = false;
this.loaded = new LinkedHashMap<>();
initializeProfiles();
while (!this.profiles.isEmpty()) {
Profile profile = this.profiles.poll();
if (isDefaultProfile(profile)) {
addProfileToEnvironment(profile.getName());
}
load(profile, this::getPositiveProfileFilter,
addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
addLoadedPropertySources();
applyActiveProfiles(defaultProperties);
});
}
/**
m4: org.springframework.boot.context.config.ConfigFileApplicationListener.
Loader#load(org.springframework.boot.context.config.ConfigFileApplicationListener.Profile,
org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentFilterFactory,
org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentConsumer)
DocumentConsumer:当配置文件中的数据加载进来后,该对象会处理
**/
private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
/**
这里会获取配置文件路径(getSearchLocations),这个路径可以自己设置,也有默认的:
DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/,file:./config/";
也会获取配置文件名称(getSearchNames),可以自己设置,也有默认的:application bootStrap;
**/
getSearchLocations().forEach((location) -> {
boolean isDirectory = location.endsWith("/");
Set<String> names = isDirectory ? getSearchNames() : NO_SEARCH_NAMES;
names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
});
}
/**
m5: org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load(java.lang.String,
java.lang.String, org.springframework.boot.context.config.ConfigFileApplicationListener.Profile,
org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentFilterFactory,
org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentConsumer)
**/
private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,
DocumentConsumer consumer) {
if (!StringUtils.hasText(name)) {
for (PropertySourceLoader loader : this.propertySourceLoaders) {
if (canLoadFileExtension(loader, location)) {
load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
return;
}
}
throw new IllegalStateException("File extension of config file location '" + location
+ "' is not known to any PropertySourceLoader. If the location is meant to reference "
+ "a directory, it must end in '/'");
}
Set<String> processed = new HashSet<>();
/**
this.propertySourceLoaders = {ArrayList@5074} size = 4
0 = {NacosXmlPropertySourceLoader@6079} "xml"
1 = {PropertiesPropertySourceLoader@6080} "properties", "xml"
2 = {YamlPropertySourceLoader@5023} "yml", "yaml"
3 = {NacosJsonPropertySourceLoader@6081} "json"
这里会根据不同的PropertySourceLoader来拿到不同的文件后缀;
**/
for (PropertySourceLoader loader : this.propertySourceLoaders) {
for (String fileExtension : loader.getFileExtensions()) {
if (processed.add(fileExtension)) {
loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory,
consumer);
}
}
}
}
/**
m6: org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load(org.springframework.boot.env.PropertySourceLoader,
java.lang.String, org.springframework.boot.context.config.ConfigFileApplicationListener.Profile,
org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentFilter,
org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentConsumer)
**/
private void load(PropertySourceLoader loader, String location, Profile profile, DocumentFilter filter,
DocumentConsumer consumer) {
Resource[] resources = getResources(location);
for (Resource resource : resources) {
try {
if (resource == null || !resource.exists()) {
if (this.logger.isTraceEnabled()) {
StringBuilder description = getDescription("Skipped missing config ", location, resource,
profile);
this.logger.trace(description);
}
continue;
}
if (!StringUtils.hasText(StringUtils.getFilenameExtension(resource.getFilename()))) {
if (this.logger.isTraceEnabled()) {
StringBuilder description = getDescription("Skipped empty config extension ", location,
resource, profile);
this.logger.trace(description);
}
continue;
}
String name = "applicationConfig: [" + getLocationName(location, resource) + "]";
/**
这里就会真正的加载文件,这里面有一个坑:就是加载文件用的api是this.classLoader.getResourceAsStream(this.path);
假如我们应用的classpath下有两个application.yml,这个api只会加载遇到的第一个,这样就导致一些外部配置找不到;
**/
List<Document> documents = loadDocuments(loader, name, resource);
if (CollectionUtils.isEmpty(documents)) {
if (this.logger.isTraceEnabled()) {
StringBuilder description = getDescription("Skipped unloaded config ", location, resource,
profile);
this.logger.trace(description);
}
continue;
}
List<Document> loaded = new ArrayList<>();
for (Document document : documents) {
if (filter.match(document)) {
addActiveProfiles(document.getActiveProfiles());
addIncludedProfiles(document.getIncludeProfiles());
loaded.add(document);
}
}
Collections.reverse(loaded);
if (!loaded.isEmpty()) {
loaded.forEach((document) -> consumer.accept(profile, document));
if (this.logger.isDebugEnabled()) {
StringBuilder description = getDescription("Loaded config file ", location, resource,
profile);
this.logger.debug(description);
}
}
}
catch (Exception ex) {
StringBuilder description = getDescription("Failed to load property source from ", location,
resource, profile);
throw new IllegalStateException(description.toString(), ex);
}
}
}
网友评论