接着上文,我们进入 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;
        }

image

在这里的 load 方法里,有对应的 PropertiesPropertyResourceLoader 和 YamlPropertyResourceLoader 分别用于解析 (propertes、xml) 文件和 (yml、yaml) 文件。
到这里配置文件的解析已经完成。


jiao个朋友
4 声望0 粉丝