springboot源码解析之autoconfigure

说在前面

本次开始spring-boot-autoconfigure源码解析,关注“天河聊架构”查阅更多精彩源码解析文章。

 

源码解析

这里是springboot重要,也是经典实现部分。

上一篇文章组件扫描器扫描组件的时候会扫描到这个注解@SpringBootApplication

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

}

重要解析下下面的这个注解,其他注解在spring源码解析系列文章中已介绍过。

@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*注解是在加载配置的时候做判断。这里不详细介绍了。
 

进入到这个方法org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports

@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#getCandidateConfigurations

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;
   }

默认自动加载的配置在这里

# 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);
   }

下面触发自动配置事件并执行监听器,自动配置加载完毕。

 

说在最后

本次仅代表个人观点,仅供参考。

 

转载于:https://my.oschina.net/u/3775437/blog/3029543

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值