【Springboot深入解析】框架啓動流程

文章僅從源碼的角度探討springboot2.x的原理,不探討使用。

我們知道Springboot是靠着這段代碼進行啓動的。

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

分析源碼的話,理所當然從這裏下手。

通過定位到源碼,我們發現這裏有兩步。一步是初始化SpringApplication對象,一步是調用run方法進行來完成啓動。

    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

對於SpringApplication初始化的源碼,主要就是對相關的屬性進行賦值。(this.xxx = xxx)

下面看一下run方法,它的內容非常簡短:

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            this.configureIgnoreBeanInfo(environment);
            Banner printedBanner = this.printBanner(environment);
            context = this.createApplicationContext();
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }

表面上看只有三十多行代碼,其實背後的代碼量是非常高的。

上面我們大致清楚了springboot的啓動,本質就是初始化SpringApplication對象後,調用run方法。在扣細節之前,有必要整體認識一下springboot啓動做了哪些事情:

框架初始化分爲:

  1. 配置資源加載器
  2. 配置primarySources(一般是我們的啓動類)
  3. 應用環境的檢測(springboot1.x版本有兩種環境,標準環境和web環境,spingboot2.x添加了一種Reactive環境)
  4. 配置系統初始化器
  5. 配置應用監聽器
  6. 配置main方法所在類

接着就是框架的基本啓動

  1. 計時器開始計時
  2. Headless模式賦值
  3. 發送ApplicationStartingEvent
  4. 配置環境模塊
  5. 發送ApplicationEnvironmentPreparedEvent
  6. 打印banner
  7. 創建應用上下文對象
  8. 初始化失敗分析器
  9. 關聯springboot組件與應用上下文對象
  10. 發送ApplicationContextInitalizedEvent
  11. 加載sources到context
  12. 發送ApplicationPreparedEvent
  13. 刷新上下文(完成bean的加載)
  14. 計時器停止計時
  15. 發送ApplicationStartedEvent事件
  16. 調用框架啓動擴展類
  17. 發送ApplicationReadyEvent

通過以上步驟完成基本的啓動,後面還有框架的自動化裝配的內容:
  1. 收集配置文件中的配置工廠類
  2. 加載組件工廠
  3. 註冊組件內定義 bean

文字描述,可能不太直觀,這裏用圖示整體梳理一下:
在這裏插入圖片描述

下面一起扣細節吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章