ConfigFileApplicationListener

实现了resources的加载工作

一句话概述:
ConfigFileApplicationListener加载file:./config,file:,classpath:/config,classpath:。这4个路径下的application命名的配置文件。
通过PropertiesPropertySourceLoader来加载后缀是"properties", "xml"的文件。
通过YamlPropertySourceLoader来加载后缀是"yml", "yaml"的文件。
所有加载的配置放在OriginTrackedMapPropertySource对象中,最后被封装成Document数组对象,随后获取到profile(spring:profiles:active:dev),加载对应的profile文件(如:application-dev.yaml),最终封装到ConfigurableEnvironment中返回,如下图

ConfigurableEnvironment.png

代码

SpringApplication

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
        // Create and configure the environment
        // 创建 ConfigurableEnvironment 对象,并进行配置
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        // 通知 SpringApplicationRunListener 的数组,环境变量已经准备完成。
        listeners.environmentPrepared(environment);
        // 绑定 environment 到 SpringApplication 上
        bindToSpringApplication(environment);
        // 如果非自定义 environment ,则根据条件转换
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
        }
        // 如果有 attach 到 environment 上的 MutablePropertySources ,则添加到 environment 的 PropertySource 中。
        ConfigurationPropertySources.attach(environment);
        return environment;
    }

listeners.environmentPrepared(environment);

通知一下监听ConfigFileApplicationListener的onApplicationEvent方法


private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        // 加载指定类型 EnvironmentPostProcessor 对应的,在 `META-INF/spring.factories` 里的类名的数组
        List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
        // 加入自己
        postProcessors.add(this);
        // 排序 postProcessors 数组
        AnnotationAwareOrderComparator.sort(postProcessors);
        // 遍历 postProcessors 数组,逐个执行。
        for (EnvironmentPostProcessor postProcessor : postProcessors) {
            //@2
            postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
        }
    }
Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
            this.environment = environment;
            // 创建 PropertySourcesPlaceholdersResolver 对象
            this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
            // 创建 DefaultResourceLoader 对象
            this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
            // 加载指定类型 PropertySourceLoader 对应的,在 `META-INF/spring.factories` 里的类名的数组
            this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader());
        }
public void load() {
            // 初始化变量
            this.profiles = new LinkedList<>(); // 未处理的 Profile 集合
            this.processedProfiles = new LinkedList<>(); // 已处理的 Profile 集合
            this.activatedProfiles = false;
            this.loaded = new LinkedHashMap<>();
            // 初始化 Spring Profiles 相关
            initializeProfiles();
            // 遍历 profiles 数组
            while (!this.profiles.isEmpty()) {
                // 获得 Profile 对象
                Profile profile = this.profiles.poll();
                // 添加 Profile 到 environment 中
                if (profile != null && !profile.isDefaultProfile()) {
                    addProfileToEnvironment(profile.getName());
                }
                // 加载配置
                load(profile, this::getPositiveProfileFilter,
                        addToLoaded(MutablePropertySources::addLast, false));
                // 添加到 processedProfiles 中,表示已处理
                this.processedProfiles.add(profile);
            }
            // 获得真正加载的 Profile 们,添加到 environment 中。
            resetEnvironmentProfiles(this.processedProfiles);
            // 加载配置
            load(null, this::getNegativeProfileFilter,
                    addToLoaded(MutablePropertySources::addFirst, true));
            // 将加载的配置对应的 MutablePropertySources 到 environment 中
            addLoadedPropertySources();
        }
private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
            // 获得要检索配置的路径
            getSearchLocations().forEach((location) -> {
                // 判断是否为文件夹
                boolean isFolder = location.endsWith("/");
                // 获得要检索配置的文件名集合
                Set<String> names = isFolder ? 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) {
            // 默认情况下,name 为 DEFAULT_NAMES=application
            if (!StringUtils.hasText(name)) {
                for (PropertySourceLoader loader : this.propertySourceLoaders) {
                    if (canLoadFileExtension(loader, location)) {
                        load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer);
                        return;
                    }
                }
            }
            Set<String> processed = new HashSet<>(); // 已处理的文件后缀集合
            // 遍历 propertySourceLoaders 数组,逐个使用 PropertySourceLoader 读取配置
            for (PropertySourceLoader loader : this.propertySourceLoaders) {
                // 遍历每个 PropertySourceLoader 可处理的文件后缀集合
                for (String fileExtension : loader.getFileExtensions()) {
                    // 添加到 processed 中,一个文件后缀,有且仅能被一个 PropertySourceLoader 所处理
                    if (processed.add(fileExtension)) {
                        // 加载 Profile 指定的配置文件(带后缀)
                        loadForFileExtension(loader, location + name, "." + fileExtension,
                                profile, filterFactory, consumer);
                    }
                }
            }
        }
private void loadForFileExtension(PropertySourceLoader loader, String prefix,
                String fileExtension, Profile profile,
                DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
            // 获得 DocumentFilter 对象
            DocumentFilter defaultFilter = filterFactory.getDocumentFilter(null);
            DocumentFilter profileFilter = filterFactory.getDocumentFilter(profile);
            // 加载 Profile 指定的配置文件(带后缀)。
            if (profile != null) {
                // Try profile-specific file & profile section in profile file (gh-340)
                // 加载 Profile 指定的配置文件(带后缀)。
                String profileSpecificFile = prefix + "-" + profile + fileExtension;
                load(loader, profileSpecificFile, profile, defaultFilter, consumer); // 情况一,未配置 spring.profile 属性
                load(loader, profileSpecificFile, profile, profileFilter, consumer); // 情况二,有配置 spring.profile 属性
                // Try profile specific sections in files we've already processed
                // 特殊情况,之前读取 Profile 对应的配置文件,也可被当前 Profile 所读取。
                // 举个例子,假设之前读取了 Profile 为 common 对应配置文件是 application-common.properties ,里面配置了 spring.profile=dev,prod
                //         那么,此时如果读取的 Profile 为 dev 时,也能读取 application-common.properties 这个配置文件
                for (Profile processedProfile : this.processedProfiles) {
                    if (processedProfile != null) {
                        String previouslyLoaded = prefix + "-" + processedProfile + fileExtension; // 拼接之前的配置文件名
                        load(loader, previouslyLoaded, profile, profileFilter, consumer); // 注意噢,传入的 profile 是当前的 profile
                    }
                }
            }
            // Also try the profile-specific section (if any) of the normal file
            // 加载(无需带 Profile)指定的配置文件(带后缀)。
            load(loader, prefix + fileExtension, profile, profileFilter, consumer);
        }
private void load(PropertySourceLoader loader, String location, Profile profile, DocumentFilter filter, DocumentConsumer consumer) {
            try {
                // 判断指定的配置文件是否存在。若不存在,则直接返回
                Resource resource = this.resourceLoader.getResource(location);
                if (!resource.exists()) {
                    if (this.logger.isTraceEnabled()) {
                        StringBuilder description = getDescription("Skipped missing config ", location, resource, profile);
                        this.logger.trace(description);
                    }
                    return;
                }
                // 如果没有文件后缀的配置文件,则忽略,不进行读取
                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);
                    }
                    return;
                }
                // 加载配置文件,返回 Document 数组
                String name = "applicationConfig: [" + location + "]";
                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);
                    }
                    return;
                }
                // 使用 DocumentFilter 过滤匹配的 Document ,添加到 loaded 数组中。
                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);
                // 使用 DocumentConsumer 进行消费 Document ,添加到本地的 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) {
                throw new IllegalStateException("Failed to load property "
                        + "source from location '" + location + "'", ex);
            }
        }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容