SpringBoot /.properties配置文件加载过程
public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
...
@Override
public void onApplicationEvent(ApplicationEvent event) {
// 向下转型
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
// 获取所有的EnvironmentPostProcessor对象
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
// this对象也是一个EnvironmentPostProcessor,加入
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
// 遍历进行环境后置处理
// 当处理到this时,加载文件,会调用
postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
}
}
...
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
addPropertySources(environment, application.getResourceLoader());
}
protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
// 正式开始load
new Loader(environment, resourceLoader).load();
}
}
// 这里用来循环location,点开getSearchLocations()可以看到配置文件的路径搜索顺序(LinkedHashSet是有序的)如下:
// "file:./config/"
// "file:./config/*/"
// "file:./"
// "classpath:/config/"
// "classpath:/"
private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
getSearchLocations().forEach((location) -> {
boolean isDirectory = location.endsWith("/");
// 用来循环配置文件名称,一般只有一个就是application,除非设置项
Set<String> names = isDirectory ? getSearchNames() : NO_SEARCH_NAMES;
names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
});
}
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<>();
// PropertySourceLoader有两个实现类:PropertiesPropertySourceLoader和YamlPropertySourceLoader
// 前者用于搜索properties和xml文件
// 后者用于搜索yml和yaml文件
for (PropertySourceLoader loader : this.propertySourceLoaders) {
// 遍历后缀文件名,
for (String fileExtension : loader.getFileExtensions()) {
if (processed.add(fileExtension)) {
// 这里load
loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory,
consumer);
}
}
}
}