springboot源碼解析之autoconfigure

說在前面spring

本次開始spring-boot-autoconfigure源碼解析,關注「天河聊架構」查閱更多精彩源碼解析文章。springboot

 

源碼解析架構

這裏是springboot重要,也是經典實現部分。mvc

上一篇文章組件掃描器掃描組件的時候會掃描到這個註解@SpringBootApplicationapp

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

重要解析下下面的這個註解,其餘註解在spring源碼解析系列文章中已介紹過。ide

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

springboot的autoconfigure主要是依賴@EnableAutoConfiguration實現。固然還有其餘輔助的註解,如@ConditionalOnClass這個註解,判斷指定的類是否在classpath下,爲何你引入了相關的包就會把相關的環境配置初始化好是這個註解在檢查你引入了哪些依賴包,如springmvc的等等。好比還有@ConditionalOnProperty註解,判斷屬性是否配置了指定的值,根據配置的指定值來加載相關配置,固然還有一些@Conditional*註解是在加載配置的時候作判斷。這裏不詳細介紹了。
 spring-boot

進入到這個方法org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImportsthis

@Override
   public String[] selectImports(AnnotationMetadata annotationMetadata) {
      if (!isEnabled(annotationMetadata)) {
         return NO_IMPORTS;
      }
      try {
         AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
               .loadMetadata(this.beanClassLoader);
         AnnotationAttributes attributes = getAttributes(annotationMetadata);
//       =》
         List<String> configurations = getCandidateConfigurations(annotationMetadata,
               attributes);
         configurations = removeDuplicates(configurations);
         configurations = sort(configurations, autoConfigurationMetadata);
//       解析排除的自動化配置
         Set<String> exclusions = getExclusions(annotationMetadata, attributes);
         checkExcludedClasses(configurations, exclusions);
         configurations.removeAll(exclusions);
//       過濾自動化配置
         configurations = filter(configurations, autoConfigurationMetadata);
         fireAutoConfigurationImportEvents(configurations, exclusions);
         return configurations.toArray(new String[configurations.size()]);
      }
      catch (IOException ex) {
         throw new IllegalStateException(ex);
      }
   }

進入到這個方法org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getCandidateConfigurationsspa

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
         AnnotationAttributes attributes) {
//    從META-INF/spring.factories路徑下加載EnableAutoConfiguration配置的類
      List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
            getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
      Assert.notEmpty(configurations,
            "No auto configuration classes found in META-INF/spring.factories. If you "
                  + "are using a custom packaging, make sure that file is correct.");
      return configurations;
   }

默認自動加載的配置在這裏token

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\

這裏不一一介紹。

返回到這個方法org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getExclusions去除@SpringBootApplication註解上指定加載的默認配置類

protected Set<String> getExclusions(AnnotationMetadata metadata,
      AnnotationAttributes attributes) {
   Set<String> excluded = new LinkedHashSet<String>();
   excluded.addAll(asList(attributes, "exclude"));
   excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
   excluded.addAll(getExcludeAutoConfigurationsProperty());
   return excluded;
}

進入這個方法org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getExcludeAutoConfigurationsProperty

private List<String> getExcludeAutoConfigurationsProperty() {
      if (getEnvironment() instanceof ConfigurableEnvironment) {
//       解析application.properties配置文件中spring.autoconfigure.exclude 屬性
         RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
               this.environment, "spring.autoconfigure.");
         Map<String, Object> properties = resolver.getSubProperties("exclude");
         if (properties.isEmpty()) {
            return Collections.emptyList();
         }
         List<String> excludes = new ArrayList<String>();
         for (Map.Entry<String, Object> entry : properties.entrySet()) {
            String name = entry.getKey();
            Object value = entry.getValue();
            if (name.isEmpty() || name.startsWith("[") && value != null) {
               excludes.addAll(new HashSet<String>(Arrays.asList(StringUtils
                     .tokenizeToStringArray(String.valueOf(value), ","))));
            }
         }
         return excludes;
      }
      RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(getEnvironment(),
            "spring.autoconfigure.");
      String[] exclude = resolver.getProperty("exclude", String[].class);
      return Arrays.asList((exclude != null) ? exclude : new String[0]);
   }

進入這個方法org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#filter

private List<String> filter(List<String> configurations,
         AutoConfigurationMetadata autoConfigurationMetadata) {
      long startTime = System.nanoTime();
      String[] candidates = configurations.toArray(new String[configurations.size()]);
      boolean[] skip = new boolean[candidates.length];
      boolean skipped = false;
//    從META-INF/spring.factories路徑加載AutoConfigurationImportFilter,解析 @ConditionalOnClass 判斷classpath路徑下有指定類,
//           @ConditionalOnMissingClass classpath路徑下沒有指定註解,進行初始化applicationContext前的校驗
      for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
         invokeAwareMethods(filter);
         boolean[] match = filter.match(candidates, autoConfigurationMetadata);
         for (int i = 0; i < match.length; i++) {
            if (!match[i]) {
               skip[i] = true;
               skipped = true;
            }
         }
      }
      if (!skipped) {
         return configurations;
      }
      List<String> result = new ArrayList<String>(candidates.length);
      for (int i = 0; i < candidates.length; i++) {
         if (!skip[i]) {
            result.add(candidates[i]);
         }
      }
      if (logger.isTraceEnabled()) {
         int numberFiltered = configurations.size() - result.size();
         logger.trace("Filtered " + numberFiltered + " auto configuration class in "
               + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)
               + " ms");
      }
      return new ArrayList<String>(result);
   }

下面觸發自動配置事件並執行監聽器,自動配置加載完畢。

 

說在最後

本次僅表明我的觀點,僅供參考。

相關文章
相關標籤/搜索