Springboot @Configuration與自動配置詳解

不知道大傢第一次搭SpringBoot環境的時候,有沒有覺得非常簡單。無須各種的配置文件,無須各種繁雜的pom坐標,一個main方法,就能run起來瞭。與其他框架整合也賊方便,使用EnableXXXXX註解就可以搞起來瞭!

所以今天來講講SpringBoot是如何實現自動配置的~

@SpringBootApplication: Spring Boot應用標註在某個類上說明這個類是SpringBoot的主配置類,SpringBoot需要運行這個類的main方法來啟動SpringBoot應用;

先看一下@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 {

註解說明:

@SpringBootConfiguration:

Spring Boot的配置類;標註在某個類上,表示這是一個Spring Boot的配置類(對@Configuration做瞭繼承,目的隻是標識是springboot的配置類);

@EnableAutoConfiguration:

開啟自動配置功能的關鍵註解,就是通過這個註解把所需的bean自動裝配到spring容器中。

再看一下這個註解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

其中有一個通過@Import註解導入瞭一個重要的對象AutoConfigurationImportSelector,它實現瞭DeferredImportSelector接口,

關於這個接口的的作用是延遲導入所有自動裝配的BeanDefinition,把這些BeanDefinition和生成的bean對比其它的bean是放在最後導入,這樣後面使用springboot封裝的@ConditionalOnBean、@ConditionalOnMissingBean 、@ConditionalOnClass、@ConditionalOnMissingClass、@ConditionalOnProperty判斷這個類需不需要裝配具有前提條件。

例如:如果我們自己在項目中配置類mybatis的SqlSessionFactory對象,則springboot中則不會再進行自動裝配,

自定義

@Bean

Public SqlSessionFactory getSqlSessionFactory (){

Return sqlSessionFactory ;

}

再看一下AutoConfigurationImportSelector對象:

其實現瞭延遲導入bean的接口DeferredImportSelector

這個可以往spring容器中註入對象。

String[] selectImports(AnnotationMetadata annotationMetadata) 此方法是在public Class<? extends Group> getImportGroup() 方法返回null的情況下,才執行生效的。否則不生效,所以此方法不做特別講解。

主要看實現的方法:

@Override
public Class<? extends Group> getImportGroup() {
   return AutoConfigurationGroup.class;
}

在spring中會執行AutoConfigurationGroup類的process方法,先分析此方法的作用:

@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
   Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
         () -> String.format("Only %s implementations are supported, got %s",
               AutoConfigurationImportSelector.class.getSimpleName(),
               deferredImportSelector.getClass().getName()));
//在此方法中找到候選自動轉入的bean的class的name。
   AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
         .getAutoConfigurationEntry(annotationMetadata);
   this.autoConfigurationEntries.add(autoConfigurationEntry);
   for (String importClassName : autoConfigurationEntry.getConfigurations()) {
      this.entries.putIfAbsent(importClassName, annotationMetadata);
   }
}

此方法的作用是找出所有候選的需要自動裝配bean的class對象名字;都封裝在AutoConfigurationEntry對象中,然後裝入全局變量中待後面方法的使用。

看一下如何找到候選待裝配的bean,調用下面的方法:

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
//此方法就是獲取註解中設置的排除裝配的bean
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
//此方法就是獲取所有的候選的bean
   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//根據名稱去重
   configurations = removeDuplicates(configurations);
//獲取排除的Bean
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   checkExcludedClasses(configurations, exclusions);
//進行排除
   configurations.removeAll(exclusions);
//這一步也是比較重要的,就是根據那些@Condition註解從候選的class中選擇符合條件的
   configurations = getConfigurationClassFilter().filter(configurations);
//執行自動導入的監聽事件AutoConfigurationImportListener
   fireAutoConfigurationImportEvents(configurations, exclusions);
   return new AutoConfigurationEntry(configurations, exclusions);
}

那如何獲取到合適的class的呢?

1、是獲取項目中(pom.xml導入jar包)META-INF/spring.factories文件中配置的的所有key-value

2、所以找到Map<String, List>類型的數據;

3、根據可以org.springframework.boot.autoconfigure.EnableAutoConfiguration作為key找到其中的List數據;

4、這些就是所有候選的class的名字

如下就是候選的class

configurations = getConfigurationClassFilter().filter(configurations);

這一步是根據候選class中的以@Condition開頭註解來過濾合適的自動裝配的bean。

先獲取三個如果所示的過濾器對象;然後傳入所有候選的class名字進行過濾,返回合適的自動裝配的bean,以mybatis為例:

根據這些條件進行過濾是否裝入bean;

最後一List返回所有符合條件的配置類;也會在list組內進行排序:根據@Order、@AutoConfigureAfter、@AutoConfigureBefore註解進行排序

AutoConfigurationGroup#selectImports

我們可以看到過濾完之後,隻剩下少量作為的對象作為配置類;

總結:

Spring自動裝配的原理是:

1、通過延遲導入bean的對象DeferredImportSelector批量的把符合條件的配置類class名稱進行返回;

2、然後根據上步返回的class名稱,也就是組件的配置類全限定名,把組件的配置對象裝配到spring容器中;

3、而springboot篩選合適的組件配置類是通過獲取META-INF/spring.factorys文件下key為org.springframework.boot.autoconfigure.EnableAutoConfiguration

的calss名稱value隻集合,然後根據這些class上面的相關以@ConditionalOn

開通的註解來過濾正在的配置類的class名稱進行返回。

@xxxConditional根據當前不同的條件判斷,決定這個配置類是否生效?

@Conditional派生註解(Spring註解版原生的@Conditional作用)

作用:必須是@Conditional指定的條件成立,才給容器中添加組件,配置配裡面的所有內容才生效;

到此這篇關於Springboot @Configuration與自動配置詳解的文章就介紹到這瞭,更多相關Springboot @Configuration內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: