天天看點

SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程

@SpringBootApplication  : 是Sprnig Boot項目的核心注解,目的是開啟自動配置

目錄

@SpringBootApplication  : 是Sprnig Boot項目的核心注解,目的是開啟自動配置

(一)、@ComponentScan 注解

(二)、@EnableAutoConfiguration 注解

(三)、@SpringBootConfiguration 注解

(四)、@Inherited 注解

聲明的此注解使用了Inherited元注解,表示此注解用在類上時,會被子類所繼承

(五)、@Documented 注解

(六)、@Retention() 注解

(七)、@Target()  注解

                     深入探索SpringApplication執行流程

spingboot建議的目錄結果如下:

root package結構:com.example.myproject

SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程
SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程

大家可以先認識一下@interface  : java 中@interface 和interface 的差別

(一)、@ComponentScan 注解

@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
           

1、@ComponentScan這個注解在Spring中很重要,它對應XML配置中的元素,@ComponentScan的功能其實就是自動掃描并加載符合條件的元件(比如@Component和@Repository等)或者bean定義,最終将這些bean定義加載到IoC容器中。

我們可以通過basePackages等屬性來細粒度的定制@ComponentScan自動掃描的範圍,如果不指定,則預設Spring架構實作會從聲明@ComponentScan所在類的package進行掃描。

注:是以SpringBoot的啟動類最好是放在root package下,因為預設不指定basePackages。

2、@ComponentScan告訴Spring 哪個packages 的用注解辨別的類 會被spring自動掃描并且裝入bean容器。

例如,如果你有個類用@Controller注解辨別了,那麼,如果不加上@ComponentScan,自動掃描該controller,那麼該Controller就不會被spring掃描到,更不會裝入spring容器中,是以你配置的這個Controller也沒有意義。

3、參數的作用

basePackageClasses:對basepackages()指定掃描注釋元件包類型安全的替代。

excludeFilters:指定不适合元件掃描的類型。

includeFilters:指定哪些類型有資格用于元件掃描。

lazyInit:指定是否應注冊掃描的beans為lazy初始化。

nameGenerator:用于在Spring容器中的檢測到的元件命名。

resourcePattern:控制可用于元件檢測的類檔案。

scopedProxy:指出代理是否應該對檢測元件産生,在使用過程中會在代理風格時尚的範圍是必要的。

scopeResolver:用于解決檢測到的元件的範圍。

useDefaultFilters:訓示是否自動檢測類的注釋 
           

(二)、@EnableAutoConfiguration 注解

@EnableAutoConfiguration 簡單概括一下就是,借助@Import的支援,收集和注冊特定場景相關的bean定義。

  • @EnableScheduling是通過@Import将Spring排程架構相關的bean定義都加載到IoC容器。
  • @EnableMBeanExport是通過@Import将JMX相關的bean定義加載到IoC容器。

而@EnableAutoConfiguration也是借助@Import的幫助,将所有符合自動配置條件的bean定義加載到IoC容器,僅此而已!

@EnableAutoConfiguration作為一個複合Annotation,其自身定義關鍵資訊如下:

SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程

其中,最關鍵的要屬@Import(AutoConfigurationImportSelector.class),借助AutoConfigurationImportSelector,@EnableAutoConfiguration可以幫助SpringBoot應用将所有符合條件的@Configuration配置都加載到目前SpringBoot建立并使用的IoC容器。

SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程

自動配置幕後英雄:SpringFactoriesLoader詳解

       SpringFactoriesLoader屬于Spring架構私有的一種擴充方案,其主要功能就是從指定的配置檔案META-INF/spring.factories加載配置。

SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程

        配合@EnableAutoConfiguration使用的話,它更多是提供一種配置查找的功能支援,即根據@EnableAutoConfiguration的完整類名org.springframework.boot.autoconfigure.EnableAutoConfiguration作為查找的Key,擷取對應的一組@Configuration類

SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程

上圖就是從SpringBoot的autoconfigure依賴包中的META-INF/spring.factories配置檔案中摘錄的一段内容,可以很好地說明問題。

        是以,@EnableAutoConfiguration自動配置的魔法騎士就變成了:從classpath中搜尋所有的META-INF/spring.factories配置檔案,并将其中org.springframework.boot.autoconfigure.EnableutoConfiguration對應的配置項通過反射(Java Refletion)執行個體化為對應的标注了@Configuration的JavaConfig形式的IoC容器配置類,然後彙總為一個并加載到IoC容器。

(三)、@SpringBootConfiguration 注解

@SpringBootConfiguration繼承自@Configuration,二者功能也一緻,标注目前類是配置類,
并會将目前類内聲明的一個或多個以@Bean注解标記的方法的執行個體納入到spring容器中,并且執行個體名就是方法名。
           

(四)、@Inherited 注解

關于java中元注解Inherited 的使用說明

首先解釋下元注解,就是用來中聲明注解類型時需要使用到的注解。

Inherited作用是,使用此注解聲明出來的自定義注解,在使用此自定義注解時,如果注解在類上面時,子類會自動繼承此注解,否則的話,子類不會繼承此注解。這裡一定要記住,使用Inherited聲明出來的注解,隻有在類上使用時才會有效,對方法,屬性等其他無效。

SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程

聲明的此注解使用了Inherited元注解,表示此注解用在類上時,會被子類所繼承

(五)、@Documented 注解

        Documented注解表明這個注釋是由 javadoc記錄的,在預設情況下也有類似的記錄工具。 如果一個類型聲明被注釋了文檔化,它的注釋成為公共API的一部分。

(六)、@Retention() 注解

RetentionPolicy這個枚舉類型的常量描述保留注釋的各種政策,它們與元注釋(@Retention)一起指定注釋要保留多長時間

(七)、@Target()  注解

ElementType 這個枚舉類型的常量提供了一個簡單的分類:注釋可能出現在Java程式中的文法位置(這些常量與元注釋類型(@Target)一起指定在何處寫入注釋的合法位置)

===========================================================================================

===========================================================================================

                     深入探索SpringApplication執行流程

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。   【banner:英文廣告橫幅,在這裡面指的是運作時輸出的SpringBoot,還可以進行修改】

SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程

6) 根據使用者是否明确設定了applicationContextClass類型以及初始化階段的推斷結果,決定該為目前SpringBoot應用建立什麼類型的ApplicationContext并建立完成,然後根據條件決定是否添加ShutdownHook,決定是否使用自定義的BeanNameGenerator,決定是否使用自定義的ResourceLoader,當然,最重要的,将之前準備好的Environment設定給建立好的ApplicationContext使用。  【ShutdownHook :停止服務】

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()方法,隻不過這種情況下會将異常資訊一并傳入處理)

去除事件通知點後,整個流程如下:

SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程
SpringBoot 啟動類 @SpringBootApplication 注解 以及執行流程                     深入探索SpringApplication執行流程

參考:

1、Spring Boot幹貨系列:(三)啟動原了解析

2、@componentscan注解的用法和作用 

3、excludeFilters:  

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html#excludeFilters--

4、@SpringBootConfiguration注解

5、關于java 注解中元注解Inherited的使用詳解

6、Java注解之 @Target、@Retention、@Documented簡介

繼續閱讀