SpringBoot /.properties配置文件加载过程

时间:2025-02-13 09:51:43
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); } } } }