1. 程式人生 > >SpringBoot原始碼分析之---SpringBoot專案啟動類SpringApplication淺析

SpringBoot原始碼分析之---SpringBoot專案啟動類SpringApplication淺析

原始碼版本

本文原始碼採用版本為SpringBoot 2.1.0BUILD,對應的SpringFramework 5.1.0.RC1

注意:本文只是從整體上梳理流程,不做具體深入分析

SpringBoot入口類

@SpringBootApplication 
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

這是我們日常使用springboot開發見到次數最多的引導類了,完成這個類的編寫,就完成了一個springboot專案的框架,springboot就回自動為我們完成一些預設配置,並幫我們初始化上下文容器,但細節我們是不知道的,下面我們就一起探索下SpringApplication.run(DemoApplication .class, args);

這行程式碼背後的故事!

SpringApplication初始化階段

public SpringApplication(Class<?>... primarySources) {
    this(null, primarySources);
}

// 初始化準備階段
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null"
); // 引數初始化 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 推斷應用型別 this.webApplicationType = deduceWebApplicationType(); // 載入ApplicationContextInitializer系列初始化器(從spring.factories檔案載入,並例項化和排序後存到this.initializers) setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); // 載入ApplicationListener系列監聽器(從spring.factories檔案載入,並例項化和排序後存到this.listeners)
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 推斷應用入口類(main函式所在類) this.mainApplicationClass = deduceMainApplicationClass(); }

推斷應用型別

// 推斷應用型別
this.webApplicationType = deduceWebApplicationType();
private WebApplicationType deduceWebApplicationType() {
    if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
            && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
            && !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : WEB_ENVIRONMENT_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}
private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
        + "web.reactive.DispatcherHandler";

private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
        + "web.servlet.DispatcherServlet";

private static final String JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig";

private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
        "org.springframework.web.context.ConfigurableWebApplicationContext" };

根據當前應用ClassPath下是否存在相關類,來確定應用型別。

載入ApplicationContextInitializer系列初始化器

// 載入ApplicationContextInitializer系列初始化器(從spring.factories檔案載入,並例項化和排序後存到this.initializers)
setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));
public void setInitializers(
        Collection<? extends ApplicationContextInitializer<?>> initializers) {
    this.initializers = new ArrayList<>();
    this.initializers.addAll(initializers);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
        Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // Use names and ensure unique to protect against duplicates
    Set<String> names = new LinkedHashSet<>(
            SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
            classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
        Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
        Set<String> names) {
    List<T> instances = new ArrayList<>(names.size());
    for (String name : names) {
        try {
            Class<?> instanceClass = ClassUtils.forName(name, classLoader);
            Assert.isAssignable(type, instanceClass);
            Constructor<?> constructor = instanceClass
                    .getDeclaredConstructor(parameterTypes);
            T instance = (T) BeanUtils.instantiateClass(constructor, args);
            instances.add(instance);
        }
        catch (Throwable ex) {
            throw new IllegalArgumentException(
                    "Cannot instantiate " + type + " : " + name, ex);
        }
    }
    return instances;
}

利用Spring工廠載入機制,例項化ApplicationContextInitializer介面的實現類,被載入的實現類都配置在MATE-INF/spring.factories檔案中,getSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, Object... args)這個方法就負責載入配置類並例項化和排序後返回,後面監聽器、異常收集器和Runner等也是通過這個類實現例項化對應實現類的。下面是spring-boot-autoconfigure\src\main\resources\META-INF\spring.factories檔案的配置內容。

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

載入ApplicationListener系列監聽器

// 載入ApplicationListener系列監聽器(從spring.factories檔案載入,並例項化和排序後存到this.listeners)
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
    this.listeners = new ArrayList<>();
    this.listeners.addAll(listeners);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}

如上面的初始化器,ApplicationListener系列監聽器也是通過getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args)
這個方法完成載入、排序及例項化的,而後存入到this.listeners中。

推斷應用入口類

// 推斷應用入口類(main函式所在類)
this.mainApplicationClass = deduceMainApplicationClass();
private Class<?> deduceMainApplicationClass() {
    try {
        // 通過new一個執行時異常獲取堆疊資訊
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            // 找到main函式所在的入口類
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}

推斷應用入口類這部分比較有意思,他是通過new了一個執行時異常來拿到main執行緒的堆疊資訊,遍歷所有方法找到main方法所在的類。

執行階段

// 執行階段
public ConfigurableApplicationContext run(String... args) {
    // 初始化容器啟動計時器
    StopWatch stopWatch = new StopWatch();
    // 開始計時
    stopWatch.start();
    // 初始化上下文ConfigurableApplicationContext
    ConfigurableApplicationContext context = null;
    // 初始化異常收集器
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    // 配置系統引數"java.awt.headless"
    configureHeadlessProperty();
    // 獲取SpringApplicationRunListener系列監聽器(從spring.factories檔案載入,並例項化和排序)
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 遍歷所有SpringApplicationRunListener系列監聽器,廣播ApplicationStartingEvent
    listeners.starting();
    try {
        // 處理args引數
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
        // 準備環境(建立、配置、繫結環境、廣播ApplicationEnvironmentPreparedEvent)
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
        configureIgnoreBeanInfo(environment);
        // 列印Banner
        Banner printedBanner = printBanner(environment);
        // 根據應用型別建立上下文
        context = createApplicationContext();
        // 獲取SpringBootExceptionReporter系列異常收集器(從spring.factories檔案載入,並例項化和排序)
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        // 上下文前置處理(執行ApplicationContextInitializer系列初始化器、載入資源、廣播ApplicationPreparedEvent)
        prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
        // 重新整理上下文()
        refreshContext(context);
        // 上下文後置處理(目前啥也沒幹)
        afterRefresh(context, applicationArguments);
        // 啟動完成,列印用時
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
        }
        // 遍歷前面設定的ConfigurableApplicationContext監聽器,釋出ApplicationStartedEvent
        listeners.started(context);
        // 按順序回撥實現了ApplicationRunner或CommandLineRunner介面的Runners
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        // 處理異常(釋出ExitCodeEvent和ApplicationFailedEvent事件、異常收集器處理異常)
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        // 遍歷前面設定好的SpringApplicationRunListener監聽器,釋出ApplicationReadyEvent
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

獲取SpringApplicationRunListener系列監聽器

// 獲取SpringApplicationRunListener系列監聽器(從spring.factories檔案載入,並例項化和排序)
SpringApplicationRunListeners listeners = getRunListeners(args);
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
            SpringApplicationRunListener.class, types, this, args));
}

這裡我們再一次見到getSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, Object... args)這個方法,功能同上。

廣播ApplicationStartingEvent事件

// 遍歷所有SpringApplicationRunListener系列監聽器,廣播ApplicationStartingEvent
listeners.starting();
public void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}
public void starting() {
    this.initialMulticaster.multicastEvent(
            new ApplicationStartingEvent(this.application, this.args));
}

這裡會遍歷上面拿到的排序好的所有SpringApplicationRunListener系列監聽器,廣播ApplicationStartingEvent事件,這代表Spring應用開始啟動,在這之前只進行了註冊化初始化器和監聽器。

準備環境、廣播ApplicationEnvironmentPreparedEvent事件

// 準備環境(建立、配置、繫結環境、廣播ApplicationEnvironmentPreparedEvent)
ConfigurableEnvironment environment = prepareEnvironment(listeners,
        applicationArguments);
private ConfigurableEnvironment prepareEnvironment(
        SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    // Create and configure the environment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    listeners.environmentPrepared(environment);
    bindToSpringApplication(environment);
    if (this.webApplicationType == WebApplicationType.NONE) {
        environment = new EnvironmentConverter(getClassLoader())
                .convertToStandardEnvironmentIfNecessary(environment);
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}
public void environmentPrepared(ConfigurableEnvironment environment) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.environmentPrepared(environment);
    }
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
    this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
            this.application, this.args, environment));
}

這裡開始建立、配置和繫結ConfigurableEnvironment環境,環境準備好之後開始遍歷SpringApplicationRunListener系列監聽器,廣播ApplicationEnvironmentPreparedEvent事件,代表環境已準備好。

開始列印Banner

// 列印Banner
Banner printedBanner = printBanner(environment);
private Banner printBanner(ConfigurableEnvironment environment) {
    // Mode.OFF:不列印banner
    if (this.bannerMode == Banner.Mode.OFF) {
        return null;
    }
    // 載入banner資源,如果自定義了banner樣式,在這裡載入,否則載入預設banner
    ResourceLoader resourceLoader = (this.resourceLoader != null)
            ? this.resourceLoader : new DefaultResourceLoader(getClassLoader());
    // 初始化bannerPrinter
    SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
            resourceLoader, this.banner);
    // Mode.LOG:通過日誌列印banner
    if (this.bannerMode == Mode.LOG) {
        return bannerPrinter.print(environment, this.mainApplicationClass, logger);
    }
    // 預設通過控制檯列印banner
    return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

關於Banner,SpringBoot支援關閉banner列印、列印到log日誌和列印到system日誌三種方式;同時支援自定義banner,自定義banner又有圖片和txt文字兩種(同時存在時先列印圖片banner,在列印文字banner),圖片banner又支援gif, jpg, png這三種類型的圖片格式banner(