SpringBoot啓動時是如何加載配置文件application.yml文件

spring加載配置文件是經過listener監視器實現的,在springboot啓動時:java

SpringApplication.javaspring

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    FailureAnalyzers analyzers = null;
    this.configureHeadlessProperty();
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting();

    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
        Banner printedBanner = this.printBanner(environment);
        context = this.createApplicationContext();
        new FailureAnalyzers(context);
        this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        this.refreshContext(context);
        this.afterRefresh(context, applicationArguments);
        listeners.finished(context, (Throwable)null);
        stopWatch.stop();
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
        }

        return context;
    } catch (Throwable var9) {
        this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
        throw new IllegalStateException(var9);
    }
}

SpringApplicationRnListeners.javaspringboot

public void finished(ConfigurableApplicationContext context, Throwable exception) {
    Iterator var3 = this.listeners.iterator();

    while(var3.hasNext()) {
        SpringApplicationRunListener listener = (SpringApplicationRunListener)var3.next();
        this.callFinishedListener(listener, context, exception);
    }

}

private void callFinishedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context, Throwable exception) {
    try {
        listener.finished(context, exception);
    } catch (Throwable var6) {
        if (exception == null) {
            ReflectionUtils.rethrowRuntimeException(var6);
        }

        if (this.log.isDebugEnabled()) {
            this.log.error("Error handling failed", var6);
        } else {
            String message = var6.getMessage();
            message = message == null ? "no error message" : message;
            this.log.warn("Error handling failed (" + message + ")");
        }
    }

}

EventPublishingRunListener.javaapp

public void finished(ConfigurableApplicationContext context, Throwable exception) {
    SpringApplicationEvent event = this.getFinishedEvent(context, exception);
    if (context != null && context.isActive()) {
        context.publishEvent(event);
    } else {
        if (context instanceof AbstractApplicationContext) {
            Iterator var4 = ((AbstractApplicationContext)context).getApplicationListeners().iterator();

            while(var4.hasNext()) {
                ApplicationListener<?> listener = (ApplicationListener)var4.next();
                this.initialMulticaster.addApplicationListener(listener);
            }
        }

        if (event instanceof ApplicationFailedEvent) {
            this.initialMulticaster.setErrorHandler(new EventPublishingRunListener.LoggingErrorHandler());
        }

        this.initialMulticaster.multicastEvent(event);
    }

}

在容器啓動完成後會廣播一個SpringApplicationEvent事件,而SpringApplicationEvent事件是繼承自ApplicationEvent時間的,因爲ConfigFileApplicationListener監聽器實現了SmartApplicationListener接口,而SmartApplicationListener接口繼承了ApplicationListener<ApplicationEvent>接口,因此能監聽到上面廣播出來的SpringApplicationEvent事件less

ConfigFileApplicationListener.javadom

public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
    this.addPropertySources(environment, application.getResourceLoader());
    this.configureIgnoreBeanInfo(environment);
    this.bindToSpringApplication(environment, application);
}

postProcessEnvironment方法是查找application.yml配置文件的入口方法ide

protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
    RandomValuePropertySource.addToEnvironment(environment);
    (new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load();
}
public void load() {
    this.propertiesLoader = new PropertySourcesLoader();
    this.activatedProfiles = false;
    this.profiles = Collections.asLifoQueue(new LinkedList());
    this.processedProfiles = new LinkedList();
    Set<ConfigFileApplicationListener.Profile> initialActiveProfiles = this.initializeActiveProfiles();
    this.profiles.addAll(this.getUnprocessedActiveProfiles(initialActiveProfiles));
    if (this.profiles.isEmpty()) {
        String[] var2 = this.environment.getDefaultProfiles();
        int var3 = var2.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String defaultProfileName = var2[var4];
            ConfigFileApplicationListener.Profile defaultProfile = new ConfigFileApplicationListener.Profile(defaultProfileName, true);
            if (!this.profiles.contains(defaultProfile)) {
                this.profiles.add(defaultProfile);
            }
        }
    }

    this.profiles.add((Object)null);

    ConfigFileApplicationListener.Profile profile;
    label41:
    for(; !this.profiles.isEmpty(); this.processedProfiles.add(profile)) {
        profile = (ConfigFileApplicationListener.Profile)this.profiles.poll();
        Iterator var8 = this.getSearchLocations().iterator();

        while(true) {
            while(true) {
                if (!var8.hasNext()) {
                    continue label41;
                }

                String location = (String)var8.next();
                if (!location.endsWith("/")) {
                    this.load(location, (String)null, profile);
                } else {
                    Iterator var10 = this.getSearchNames().iterator();

                    while(var10.hasNext()) {
                        String name = (String)var10.next();
                        this.load(location, name, profile);
                    }
                }
            }
        }
    }

    this.addConfigurationProperties(this.propertiesLoader.getPropertySources());
}

默認先讀取的是location,而後是配置文件的名字「application」,最後纔是文件類型「properties」或者「yml」;post

localtion有多種,能夠自行debug:有file:./和file:./config和classpath等目錄;ui

文件類型默認的有四種:properties、xml、yml、yaml;this

最後查找的具體路徑:location + name + "-" + profile + "." + ext;

private void load(String location, String name, ConfigFileApplicationListener.Profile profile) {
    String group = "profile=" + (profile == null ? "" : profile);
    String ext;
    if (!StringUtils.hasText(name)) {
        this.loadIntoGroup(group, location, profile);
    } else {
        for(Iterator var5 = this.propertiesLoader.getAllFileExtensions().iterator(); var5.hasNext(); this.loadIntoGroup(group, location + name + "." + ext, profile)) {
            ext = (String)var5.next();
            if (profile != null) {
                this.loadIntoGroup(group, location + name + "-" + profile + "." + ext, (ConfigFileApplicationListener.Profile)null);
                Iterator var7 = this.processedProfiles.iterator();

                while(var7.hasNext()) {
                    ConfigFileApplicationListener.Profile processedProfile = (ConfigFileApplicationListener.Profile)var7.next();
                    if (processedProfile != null) {
                        this.loadIntoGroup(group, location + name + "-" + processedProfile + "." + ext, profile);
                    }
                }

                this.loadIntoGroup(group, location + name + "-" + profile + "." + ext, profile);
            }
        }
    }

}

根據拼出來的路徑去查找配置文件,通常配置文件都放在classpath目錄下面,當讀取到classpath目錄下的配置文件的時候,程序去加載配置文件

private PropertySource<?> loadIntoGroup(String identifier, String location, ConfigFileApplicationListener.Profile profile) {
    try {
        return this.doLoadIntoGroup(identifier, location, profile);
    } catch (Exception var5) {
        throw new IllegalStateException("Failed to load property source from location '" + location + "'", var5);
    }
}

private PropertySource<?> doLoadIntoGroup(String identifier, String location, ConfigFileApplicationListener.Profile profile) throws IOException {
    Resource resource = this.resourceLoader.getResource(location);
    PropertySource<?> propertySource = null;
    StringBuilder msg = new StringBuilder();
    if (resource != null && resource.exists()) {
        String name = "applicationConfig: [" + location + "]";
        String group = "applicationConfig: [" + identifier + "]";
        propertySource = this.propertiesLoader.load(resource, group, name, profile == null ? null : profile.getName());
        if (propertySource != null) {
            msg.append("Loaded ");
            this.handleProfileProperties(propertySource);
        } else {
            msg.append("Skipped (empty) ");
        }
    } else {
        msg.append("Skipped ");
    }

    msg.append("config file ");
    msg.append(this.getResourceDescription(location, resource));
    if (profile != null) {
        msg.append(" for profile ").append(profile);
    }

    if (resource != null && resource.exists()) {
        this.logger.debug(msg);
    } else {
        msg.append(" resource not found");
        this.logger.trace(msg);
    }

    return propertySource;
}

當加載配置文件時,程序先會讀取配置文件的spring.profiles.active屬性,肯定加載什麼環境的配置文件(我是加載dev的),而後將讀取到的配置文件的屬性加載到profiles隊列中從新加載配置文件,因此任何項目都必須現有一個基礎的配置文件,如application.yml

private void handleProfileProperties(PropertySource<?> propertySource) {
    ConfigFileApplicationListener.SpringProfiles springProfiles = this.bindSpringProfiles(propertySource);
    this.maybeActivateProfiles(springProfiles.getActiveProfiles());
    this.addProfiles(springProfiles.getIncludeProfiles());
}

private ConfigFileApplicationListener.SpringProfiles bindSpringProfiles(PropertySource<?> propertySource) {
    MutablePropertySources propertySources = new MutablePropertySources();
    propertySources.addFirst(propertySource);
    return this.bindSpringProfiles((PropertySources)propertySources);
}

private ConfigFileApplicationListener.SpringProfiles bindSpringProfiles(PropertySources propertySources) {
    ConfigFileApplicationListener.SpringProfiles springProfiles = new ConfigFileApplicationListener.SpringProfiles();
    RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles, "spring.profiles");
    dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false));
    springProfiles.setActive(this.resolvePlaceholders(springProfiles.getActive()));
    springProfiles.setInclude(this.resolvePlaceholders(springProfiles.getInclude()));
    return springProfiles;
}

而後在這個配置文件裏面有一個active屬性,程序會先拿到這個屬性,放到profiles屬性中,從新去加載配置文件如application-dev.yml

private void addProfiles(Set<ConfigFileApplicationListener.Profile> profiles) {
    Iterator var2 = profiles.iterator();

    while(var2.hasNext()) {
        ConfigFileApplicationListener.Profile profile = (ConfigFileApplicationListener.Profile)var2.next();
        this.profiles.add(profile);
        if (!this.environmentHasActiveProfile(profile.getName())) {
            this.prependProfile(this.environment, profile);
        }
    }
}
相關文章
相關標籤/搜索