Spring Boot啟動流程簡述

何總會發光發表於2020-10-11

轉載連結
Spring Boot程式有一個入口,就是main方法。main裡面呼叫SpringApplication.run()啟動整個Spring Boot程式,該方法所在類需要使用@SpringBootApplication註解。

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

@SpringBootApplication包括三個註解:

1)@EnableAutoConfiguration:SpringBoot根據應用所宣告的依賴來對Spring框架進行自動配置。簡單概括一下就是藉助@Import的幫助,將所有符合自動配置條件的bean定義載入到IoC容器。
2)@Configuration:它就是JavaConfig形式的Spring Ioc容器的配置類。被標註的類等於在spring的XML配置檔案中(applicationContext.xml),裝配所有bean事務,提供了一個spring的上下文環境。
3)@CompentScan:元件掃描,可自動發現和裝配Bean,功能其實就是自動掃描並載入符合條件的元件或者 bean定義,最終將這些bean定義載入到Ioc容器中。可以通過basePackages等屬性來細粒度的定製@ComponentScan自動掃描的範圍,如果不指定,則預設Spring框架實現從宣告@ComponentScan所在類的package進行掃描。預設掃描SpringApplication的run方法裡的Booter.class所在的包路徑下檔案,所以最好將該類放到根路徑下。

執行run方法之前需要對SpringApplication進行初始化,會呼叫一個private型別的initialize方法

public SpringApplication(Object... sources){
	initialize(sources);
}

initialize方法的具體實現:

private void initialize(Object[] sources) {
      if (sources != null && sources.length > 0) {
        this.sources.addAll(Arrays.asList(sources)); // 把sources設定到SpringApplication的sources屬性中,目前只是一個MyApplication類物件
      }
      this.webEnvironment = deduceWebEnvironment(); // 判斷是否是web程式(javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext都必須在類載入器中存在),並設定到webEnvironment屬性中
      // 從spring.factories檔案中找出key為ApplicationContextInitializer的類並例項化後設定到SpringApplication的initializers屬性中。這個過程也就是找出所有的應用程式初始化器
      setInitializers((Collection) getSpringFactoriesInstances(
          ApplicationContextInitializer.class));
      // 從spring.factories檔案中找出key為ApplicationListener的類並例項化後設定到SpringApplication的listeners屬性中。這個過程就是找出所有的應用程式事件監聽器
      setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
      // 找出main類,這裡是MyApplication類
      this.mainApplicationClass = deduceMainApplicationClass();
    }

SpringBoot啟動的時候,不論呼叫什麼方法,都會構造一個SpringApplication的例項,然後呼叫這個例項的run方法,這樣就表示啟動SpringBoot。

在run方法呼叫之前,也就是構造SpringApplication的時候進行初始化工作,初始化的時候會做以下幾件事:
1,把引數sources設定到SpringApplication設定中,這個sources可以是任何型別的引數。
2,判斷是否是web程式,並設定到webEnvironment這個boolean屬性中。
3,找出所有的初始化器,預設有5個,設定到initializers屬性中。
4,找出所有的應用程式監聽器,預設有9個,設定到listenrs屬性中。
5,找出執行的主類(main class)。

SpringApplication構造完成之後會呼叫run方法,啟動SpringApplication,run方法執行的時候會做以下幾件事:
1,構造一個stopWatch,觀察SpringApplication的執行。
2,找出所有的SpringApplicationRunListeners中,用於監聽run方法的執行。監聽的過程中會封裝成事件並廣播出去讓初始化過程中產生的應用程式監聽器進行監聽。
3,構造Spring容器(ApplicationContext),並返回
3.1 建立Spring容器的判斷是否是web環境,是的話構造AnnotationConfigEmbeddedWebApplicationContext,否則構造AnnotationConfigApplicationContext。
3.2 初始化過程中產生的初始化容器在這個時候開始工作。
3.3 Spring容器的重新整理(完成bean的解析、各種processor介面的執行、條件註解的解析等等)。
4,從Spring容器中找出ApplicationRunner和CommandLineRunner介面的實現類並排序後依次執行。

引用另一版本的解釋:

SpringApplication的run方法的實現是我們本次旅程的主要線路,該方法的主要流程大體可以歸納如下:

1) 如果我們使用的是SpringApplication的靜態run方法,那麼,這個方法裡面首先要建立一個SpringApplication物件例項,然後呼叫這個建立好的SpringApplication的例項方法。在SpringApplication例項初始化的時候,它會提前做幾件事情:
根據classpath裡面是否存在某個特徵類(org.springframework.web.context.ConfigurableWebApplicationContext)來決定是否應該建立一個為Web應用使用的ApplicationContext型別。
使用SpringFactoriesLoader在應用的classpath中查詢並載入所有可用的ApplicationContextInitializer。
使用SpringFactoriesLoader在應用的classpath中查詢並載入所有可用的ApplicationListener。

推斷並設定main方法的定義類。

2) SpringApplication例項初始化完成並且完成設定後,就開始執行run方法的邏輯了,方法執行伊始,首先遍歷執行所有通過SpringFactoriesLoader可以查詢到並載入的SpringApplicationRunListener。呼叫它們的started()方法,告訴這些SpringApplicationRunListener,“嘿,SpringBoot應用要開始執行咯!”。

3) 建立並配置當前Spring Boot應用將要使用的Environment(包括配置要使用的PropertySource以及Profile)。

4) 遍歷呼叫所有SpringApplicationRunListener的environmentPrepared()的方法,告訴他們:“當前SpringBoot應用使用的Environment準備好了咯!”。

5) 如果SpringApplication的showBanner屬性被設定為true,則列印banner。

6) 根據使用者是否明確設定了applicationContextClass型別以及初始化階段的推斷結果,決定該為當前SpringBoot應用建立什麼型別的ApplicationContext並建立完成,然後根據條件決定是否新增ShutdownHook,決定是否使用自定義的BeanNameGenerator,決定是否使用自定義的ResourceLoader,當然,最重要的,將之前準備好的Environment設定給建立好的ApplicationContext使用。

7) ApplicationContext建立好之後,SpringApplication會再次藉助Spring-FactoriesLoader,查詢並載入classpath中所有可用的ApplicationContext-Initializer,然後遍歷呼叫這些ApplicationContextInitializer的initialize(applicationContext)方法來對已經建立好的ApplicationContext進行進一步的處理。

8) 遍歷呼叫所有SpringApplicationRunListener的contextPrepared()方法。

9) 最核心的一步,將之前通過@EnableAutoConfiguration獲取的所有配置以及其他形式的IoC容器配置載入到已經準備完畢的ApplicationContext。

10) 遍歷呼叫所有SpringApplicationRunListener的contextLoaded()方法。

11) 呼叫ApplicationContext的refresh()方法,完成IoC容器可用的最後一道工序。

12) 查詢當前ApplicationContext中是否註冊有CommandLineRunner,如果有,則遍歷執行它們。

13) 正常情況下,遍歷執行SpringApplicationRunListener的finished()方法、(如果整個過程出現異常,則依然呼叫所有SpringApplicationRunListener的finished()方法,只不過這種情況下會將異常資訊一併傳入處理)

去除事件通知點後,整個流程如下:
在這裡插入圖片描述

相關文章