SpringBoot是如何動起來的?

程序入口

SpringApplication.run(BeautyApplication.class, args);

  

執行此方法來加載整個SpringBoot的環境。

1. 從哪兒開始?

SpringApplication.java

    /**
     * Run the Spring application, creating and refreshing a new
     * {@link ApplicationContext}.
     * @param args the application arguments (usually passed from a Java main method)
     * @return a running {@link ApplicationContext}
     */
    public ConfigurableApplicationContext run(String... args) {
        //...
  }

 

調用SpringApplication.java 中的 run 方法,目的是加載Spring Application,同時返回 ApplicationContext。

2. 執行了什么?

2.1 計時

記錄整個Spring Application的加載時間!

StopWatch stopWatch = new StopWatch();
stopWatch.start();
// ...
stopWatch.stop();
if (this.logStartupInfo) {
    new StartupInfoLogger(this.mainApplicationClass)
            .logStarted(getApplicationLog(), stopWatch);
}

 

2.2 聲明

// 聲明 ApplicationContext
ConfigurableApplicationContext context = null;
// 聲明 一個異常報告集合
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

 

2.3 指定程序運行模式

指定 java.awt.headless,默認是true 一般是在程序開始激活headless模式,告訴程序,現在你要工作在Headless mode下,就不要指望硬件幫忙了,你得自力更生,依靠系統的計算能力模擬出這些特性來。

private void configureHeadlessProperty() {
    System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
            SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}

 

2.4 配置監聽并發布應用啟動事件

SpringApplicationRunListener 負責加載 ApplicationListener事件。

SpringApplicationRunListeners listeners = getRunListeners(args);
// 開始
listeners.starting();
// 處理所有 property sources 配置和 profiles 配置,準備環境,分為標準 Servlet 環境和標準環境
ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
// 準備應用上下文
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
// 完成
listeners.started(context);
// 異常
handleRunFailure(context, ex, exceptionReporters, listeners);
// 執行
listeners.running(context);

 

getRunListeners 中根據 type = SpringApplicationRunListener.class 去拿到了所有的 Listener 并根據優先級排序。

對應的就是 META-INF/spring.factories 文件中的 

org.springframework.boot.SpringApplicationRunListener=org.springframework.boot.context.event.EventPublishingRunListener

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;
    }

  

在 ApplicationListener 中 , 可以針對任何一個階段插入處理代碼。

public interface SpringApplicationRunListener {

    /**
     * Called immediately when the run method has first started. Can be used for very
     * early initialization.
     */
    void starting();

    /**
     * Called once the environment has been prepared, but before the
     * {@link ApplicationContext} has been created.
     * @param environment the environment
     */
    void environmentPrepared(ConfigurableEnvironment environment);

    /**
     * Called once the {@link ApplicationContext} has been created and prepared, but
     * before sources have been loaded.
     * @param context the application context
     */
    void contextPrepared(ConfigurableApplicationContext context);

    /**
     * Called once the application context has been loaded but before it has been
     * refreshed.
     * @param context the application context
     */
    void contextLoaded(ConfigurableApplicationContext context);

    /**
     * The context has been refreshed and the application has started but
     * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
     * ApplicationRunners} have not been called.
     * @param context the application context.
     * @since 2.0.0
     */
    void started(ConfigurableApplicationContext context);

    /**
     * Called immediately before the run method finishes, when the application context has
     * been refreshed and all {@link CommandLineRunner CommandLineRunners} and
     * {@link ApplicationRunner ApplicationRunners} have been called.
     * @param context the application context.
     * @since 2.0.0
     */
    void running(ConfigurableApplicationContext context);

    /**
     * Called when a failure occurs when running the application.
     * @param context the application context or {@code null} if a failure occurred before
     * the context was created
     * @param exception the failure
     * @since 2.0.0
     */
    void failed(ConfigurableApplicationContext context, Throwable exception);

}

 

3. 每個階段執行的內容

3.1 listeners.starting();

在加載Spring Application之前執行,所有資源和環境未被加載。

3.2 prepareEnvironment(listeners, applicationArguments);

創建 ConfigurableEnvironment;將配置的環境綁定到Spring Application中;

  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;
    }

 

3.3 prepareContext

配置忽略的Bean;

private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
        if (System.getProperty(
                CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
            Boolean ignore = environment.getProperty("spring.beaninfo.ignore",
                    Boolean.class, Boolean.TRUE);
            System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
                    ignore.toString());
        }
    }

 

打印日志-加載的資源

Banner printedBanner = printBanner(environment);

 

根據不同的WebApplicationType創建Context

context = createApplicationContext();

 

3.4 refreshContext

支持定制刷新

  /**
     * Register a shutdown hook with the JVM runtime, closing this context
     * on JVM shutdown unless it has already been closed at that time.
     * <p>This method can be called multiple times. Only one shutdown hook
     * (at max) will be registered for each context instance.
     * @see java.lang.Runtime#addShutdownHook
     * @see #close()
     */
    void registerShutdownHook();

 

3.5 afterRefresh

刷新后的實現方法暫未實現

   /**
     * Called after the context has been refreshed.
     * @param context the application context
     * @param args the application arguments
     */
    protected void afterRefresh(ConfigurableApplicationContext context,
            ApplicationArguments args) {
    }

 

3.6 listeners.started(context);

到此為止, Spring Application的環境和資源都加載完畢了;發布應用上下文啟動完成事件;執行所有 Runner 運行器 - 執行所有 ApplicationRunner 和 CommandLineRunner 這兩種運行器。

// 啟動
callRunners(context, applicationArguments);

 

3.7 listeners.running(context);

觸發所有 SpringApplicationRunListener 監聽器的 running 事件方法。

 

微信討論群,如果微信失效請加 shengruxiahua3596  拉你入群

 

發布于 10:09
posted @ 2019-10-26 10:14  在路上.......  閱讀(...)  評論(... 編輯 收藏
三d开奖结果走势图