接着上文,咱们进入 spring 的环境筹备办法中:

    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,            ApplicationArguments applicationArguments) {        // Create and configure the environment        ConfigurableEnvironment environment = getOrCreateEnvironment();        configureEnvironment(environment, applicationArguments.getSourceArgs());        ConfigurationPropertySources.attach(environment);        listeners.environmentPrepared(environment);        bindToSpringApplication(environment)        if (!this.isCustomEnvironment) {            environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,                    deduceEnvironmentClass());        }        ConfigurationPropertySources.attach(environment);        return environment;    }

其中 getOrCreateEnvironment 会依据以后的 webApplicationType 的类型来创立环境的类型,如果是 SERVLET 类型的话,会创立一个 StandardServletEnvironment 对象。这里的environmentPrepared 办法 ApplicationEnvironmentPreparedEvent 类型的事件。依据事件类型获取监听器,咱们来察看比拟重要的监听器:ConfigFileApplicationListener,在这个类型实现了咱们配置文件的解析。进入到其 onApplicationEvent 办法可知: 次要是获取到环境筹备的后置处理器(EnvironmentPostProcessor),并调用它们的 postProcessEnvironment 办法。值得注意的是 ConfigFileApplicationListener 本身也实现了EnvironmentPostProcessor 接口,也是 ConfigFileApplicationListener 实现了对配置文件的解析。

public void onApplicationEvent(ApplicationEvent event) {     if (event instanceof ApplicationEnvironmentPreparedEvent) {        onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);     }     if (event instanceof ApplicationPreparedEvent) {        onApplicationPreparedEvent(event);     }  }    private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {     List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();     postProcessors.add(this);     AnnotationAwareOrderComparator.sort(postProcessors);     for (EnvironmentPostProcessor postProcessor : postProcessors) {        postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());     }  }

跟进 ConfigFileApplicationListener 进入 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);                    });        }

持续进入这里的 load 办法

        private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {            getSearchLocations().forEach((location) -> {                boolean isDirectory = location.endsWith("/");                Set<String> names = isDirectory ? getSearchNames() : NO_SEARCH_NAMES;                names.forEach((name) -> load(location, name, profile, filterFactory, consumer));            });        }

这俩的 getSearchLocations 办法是获取搜寻的门路,springboot 默认的门路为:DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/*/,file:./config/";获取多个搜寻门路之后,别离调用 load 办法。

        private Set<String> getSearchLocations() {            Set<String> locations = getSearchLocations(CONFIG_ADDITIONAL_LOCATION_PROPERTY);            if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {                locations.addAll(getSearchLocations(CONFIG_LOCATION_PROPERTY));            }            else {                locations.addAll(                        asResolvedSet(ConfigFileApplicationListener.this.searchLocations, DEFAULT_SEARCH_LOCATIONS));            }            return locations;        }

在这里的 load 办法里,有对应的 PropertiesPropertyResourceLoader 和 YamlPropertyResourceLoader 别离用于解析 (propertes、xml) 文件和 (yml、yaml) 文件。
到这里配置文件的解析曾经实现。