Springboot專案中 如何獲取@Configuration註解標註的配置類

ColorPaper發表於2020-11-29
  • 整個springboot並沒有在spring的基礎上提供什麼額外的功能。

    從開發人員的角度來看,springBoot的最大作用就是引入某些jar包後,自動為spring上下文環境生成某些特定功能的Bean,這樣就可以自動提供某些相關功能。

  • 從實現的角度來看,spring通過被標記了@Configuration的類提供一些提前生成好的Bean提供特別的功能,而用@Contional系列的註解限制生成的條件,通常就是@ConditionalOnClass和@ConditionalOnMissingBean註解的配合使用。前者確定某些功能需要的class已經有了,後者確定你沒有自己生成相關的bean,才提供預設的。

  • 可以使用@AutoConfigureBefore,@AutoConfigureAfter,@AutoconfigureOrder 來確定某個自動註冊類的生效順序。作用類比@Order。

  • 自動註冊一般提供2個module:一個是autoconfigure jar包,一個是starter jar包。其中starter這種jar裡面並沒有程式碼,是空的。唯一的作用是將需要的各種jar寫入構建檔案,這樣引入此starter,就不要再去關心相應的其他jar了。

    springboot自己的starter實現是這麼幹的。

    SpringCloudNetflixZuul是將這兩者統一於一個module中來實現的

主要分成以下三個場景:

  1. @Configuration配置類在程式可以掃描到的package裡,也就是@ComponentScan註解所指定的package裡。SpringBoot工程天然支援該類配置類注入方式。

    最佳實踐:

    最佳實踐

    //@SpringBootApplication註解中含有@ComponentScan
    1 @SpringBootApplication
    2 public class Application {
    3     public static void main(String[] args) {
    4         SpringApplication.run(Application.class, args);
    5     }
    6 }
    
  2. @Configuration配置類沒有在package掃描路徑下,即不是專案開發人員自己編寫的程式碼。

    比如製作第三方包供他人在springboot專案中使用,如RPC框架、starter工程、spring-cloud-netflix-zuul等。

    最佳實踐:

    1、編寫AutoConfiguration配置類

    2、在META-INF/spring.factories裡用org.springframework.boot.autoconfigure.EnableAutoConfiguration來指定。

    spring-boot-autoconfigure包裡的配置類都是通過這種方式引入的。

    示例:

    用於在專案中匯入的第三方包spring-cloud-netflix-zuul

    image

    image

    引入spring-cloud-netflix-zuul的demo專案(實際是通過spring-cloud-starter-zuul引入的)

    當然,這個方式需要程式使用@EnableAutoConfiguration註解,這個註解是通過AutoConfigurationImportSelector來掃描spring.factories檔案,把定義的配置類引入的。

讀取spring.factories檔案的實現
是通過org.springframework.core.io.support.SpringFactoriesLoader實現的。
SpringFactoriesLoader的實現類似於SPI(Service Provider Interface)

java SPI提供一種服務發現機制,為某個介面尋找服務實現的機制。

有點類似IOC的思想,就是將裝配的控制權移到程式之外,在模組化設計中這個機制尤其重要。

實現說明:

 

1 @SpringBootApplication
2 public class Application {
3     public static void main(String[] args) {
4         SpringApplication.run(Application.class, args);
5     }
6 }

這是springboot專案中應用最常見的啟動方式,核心有兩個:

  • @SpringBootApplication註解
  • SpringApplication.run()靜態方法

和我們此處討論有關係的是註解@SpringBootApplication

@SpringBootApplication原始碼如下:

 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
     @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
     @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {....}

@ComponentScan,spring的自動掃描註解,對應方法一。

@EnableAutoConfiguration:藉助@Import的幫助,將所有符合自動配置條件的bean定義載入到IoC容器(建議放在根包路徑下,這樣可以掃描子包和類)

@EnableAutoConfiguration原始碼如下:

 

@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {....}

其核心是一個EnableAutoConfigurationImportSelector類

 

public class EnableAutoConfigurationImportSelector
     extends AutoConfigurationImportSelector {...}

核心方法在頂級介面ImportSelector的selectImports()的實現上,原始碼如下:

 

 @Override
 public String[] selectImports(AnnotationMetadata annotationMetadata) {
     if (!isEnabled(annotationMetadata)) {
         return NO_IMPORTS;
     }
     try {
          //1.從META-INF/spring-autoconfigure-metadata.properties檔案中載入配置屬性(有一些有預設值)
         AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                 .loadMetadata(this.beanClassLoader);
          //2.獲取註解屬性
         AnnotationAttributes attributes = getAttributes(annotationMetadata);
      //3.獲取自動配置類    
          List<String> configurations = getCandidateConfigurations(annotationMetadata,
                 attributes);
          //4.移除重複的
         configurations = removeDuplicates(configurations);
          //5.排序
         configurations = sort(configurations, autoConfigurationMetadata);
          //6.排出需要排出的
         Set<String> exclusions = getExclusions(annotationMetadata, attributes);
         checkExcludedClasses(configurations, exclusions);
         configurations.removeAll(exclusions);
          //6.過濾器OnClassCondition(註解中配置存在某類才生效)
         configurations = filter(configurations, autoConfigurationMetadata);
          //7.觸發自動配置匯入監聽事件
         fireAutoConfigurationImportEvents(configurations, exclusions);
         return configurations.toArray(new String[configurations.size()]);
     }
     catch (IOException ex) {
         throw new IllegalStateException(ex);
     }
 }
  1. 使用@Import註解

    這個註解可以引入三種類

    • 使用了@Configuration註解的類

      如spring-cloud-netflix中ZuulProxyAutoConfiguration通過@import匯入了若干個被@Configuration註解的類

      image

    • ImportSelector的子類(嚴格說來這不屬於被@Configuration標註的配置類這一前提,但也屬於springboot自動配置能力的一種,故羅列在此)

      如@EnableAutoConfiguration中所引入的EnableAutoConfigurationImportSelector

      image

    • ImportBeanDefinitionRegistrar的子類

      {todo}

初始spring boot

spring boot容器啟動詳解



作者:Drew_Zhong
連結:https://www.jianshu.com/p/9ecdc9ad70dc
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

相關文章