springboot(二)自動化設定原始碼解析

2020-10-12 12:00:13

     @EnableAutoConfiguration 是開啟自動設定的註解,在建立的 SpringBoot 專案中並不能直接看到此註解,它是由組合註解@SpringBootApplication 引入的。

    讓我們先從程式的啟動類開始分析. 

     啟動類和@SpringBootApplication 註解

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

      Spring Boot 專案建立完成會預設生成-個*Application 的入口類。 在預設情況下,無論是通過 IDEA 還是通過官方建立基於 Maven 的 Spring Boo 專案,入口類的命名規則都是artifactld+Application。
     這個啟動類中最重要的就是@SpringBootApplication註解. 它是 Spring Boot 專案的核心註解,用於開啟自動設定,準確說是通過該註解內組合的@EnableAutoConfiguration 開啟了自動設定。

     @SpringBootApplication 部分原始碼如下: 

   

@Target(ElementType . TYPE)
@Retent ion(Retent ionPolicy . RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan( excludeFilters = {
    @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM,classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    //排除指定自動設定類
    @AliasFor(annotation = EnableAutoConfiguration.class)
    Class<?>[] exclude() default {};
    //排除指定自動設定類名
    @AliasFor( annotation = EnableAutoConfiguration. class)
    String[] excludeName() default {}
    //指定掃描的基礎包,啟用炷解元件的初始化
    @AliasFor( annotation = ComponentScan. class, attribute = "basePackages")
    String[] scanBasePackages() default {};
    //指定掃描的類,用於初始化
    @AliasFor( annotation = ComponentScan. class, attribute = "basePackageClass")
    Class<?>[] scanBasePackageClasses() default {};
    //指定是否代理@Bean 方法以強制執行 bean 的生命週期行為
    @AliasFor( annotation = Configuration.class)
    boolean proxyBeanMethods() default true ; 
}

通過原始碼可以看出,該註解提供了以下成員屬性(註解中的成員變數以方法的形式體現)。

  1. exclude:根據類(Class) 排除指定的自動設定,該成員屬性覆蓋了@SpringBoot-Application中組合的@ EnableAutoConfiguration 中定義的 exclude 成員屬性。
  2. excludeName :根據類名排除指定的自動設定,覆蓋了@ EnableAutoConfiguration 中的excludeName 的成員屬性。
  3. scanBasePackages:指定掃描的基礎 package,用於啟用@Component 等註解類的初始化。
  4. scanBasePackageClasses:掃描指定的類,用於元件的初始化。
  5. proxyBeanMethods:指定是否代理@ Bean 方法以強制執行 bean 的生命週期行為。此功能需要通過執行時生成 CGLIB 子類來實現方法攔截。該子類有一定的限制,比如設定類及其方法不允許宣告為 final 等。
    proxyBeanMethods 的預設值為 true,允許設定類中進行 inter-beanreferences (bean 之 間的參照)以及對該設定的@Bean 方法的外部呼叫。如果@Bean 方法都是自包含的,並且僅提供了容器使用的普通工程方法的功能,則可設定為 false,避免處理 CGLIB 子類。SpringBoot 2.2 版本上市後新增該成員屬性,後面章節涉及的自動設定類中基本都會用到proxyBeanMethods,一 般情況下都設定為 false。

   通過以上原始碼我們會發現,Spring Boot 中大量使用了@AliasFor 註解,該註解用於橋接到其他註解,該註解的屬性中指定了所橋接的註解類。如果點進去檢視,會發現@SpringBootApplication 定 義的屬性在其他註解中已經定義過了。之所以使用@AliasFor註解並重新在@SpringBootApplication 中定義,更多是為了減少使用者使用多註解帶來的麻煩。
@SpringBootApplication註解的組合結構如下圖: 

    @SpringBootApplication除 了組合元註解之外,其核心作用還包括:啟用SpringBoot 自 動 配 置 的 @EnableAutoConfiguration 、 激 活 @Component 掃 描 的@ComponentScan、啟用設定類的@Configuration。其中@ComponentScan,@Configuration在Spring中常用到, 這裡分析一下@EnableAutoConfiguration的功能.


註解@EnableAutoConfiguration功能解析

       在未使用 Spring Boot 的情況下,Bean 的生命週期由 Spring 來管理,然而 Spring 無法自動設定@Configuration 註解的類。而 Spring Boot 的核心功能之- 就是根據約定自動管理該註解標註的類。用來實現該功能的元件是@EnableAutoConfiguration 註解。

        @EnableAutoConfiguration 的主要功能是啟動 Spring 應用程式上下文時進行自動設定,它會嘗試猜測並設定專案可能需要的 Bean。自動設定通常是基於專案 classpath 中引入的類和已定義的 Bean 來實現的。在此過程中,被自動設定的元件來自專案自身和專案依賴的 jar包中。

     例如: 如 果 將 tomcat-embedded.jar 添 加 到 classpath 下 , 那 麼@EnableAutoConfiguration 會認為你準備用 TomcatServletWebServerFactory 類,並幫你初始化相關設定。與此同時,如果自定義了基於 ServletWebServerFactory 的 Bean ,那麼@EnableAutoConfiguration 將不會進行 TomcatServletWebServerFactory 類的初始化。這一系列的操作判斷都由 Spring Boot 來完成。

    @EnableAutoConfiguration 註解的原始碼

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    //根據類(Class) 排除指定的自動設定
    Class<?>[] exclude() default {};
    //根據類名排除指定的自動設定
    String[] excludeName() default {};
}

    @EnableAutoConfiguration 會猜 測你需要使用的 Bean,但如果在實戰中你並不需要它預置初始化的 Bean,可通過該註解的 exclude 或 excludeName 引數進行有針對性的排除。比如,當不需要資料庫的自動設定時,可通過以下兩種方式讓其自動設定失效。

//通過@SpringBootApplication 排除 DataSourceAutoConfiguration
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class SpringLearnApplication {

}
或:
//通過@EnableAutoConfiguration 排除 DataSourceAutoConfiguration
@Configuration
@EnableAutoConfiguration( exclude = DataSourceAutoConfiguration.class)
public class DemoConfiguration {

}

    被@EnableAutoConfiguration 注 解的類所在 package 還具有特定的意義,通常會被作為掃描註解@Entity 的根路徑。這也是在使用@SpringBootApplication 註解時需要將被註解的類放在頂級 package 下的原因,如果放在較低層級,它所在 package 的同級或上級中的類就無法被掃描到。