@SpringBootApplication 注解解析

@SpringBootApplication 注解解析

使用springboot第一步都是添加@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 {
    ......
}

看源码可以看出 主要的注解有三个
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

首先@SpringBootConfiguration这个注解:

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

可以看出@SpringBootConfiguration就是@Configuration注解的再套一层,本质上还是@Configuration,而@Configuration注解的作用就是javaConfig形式的配置类,用于spring ioc容器,springbooot使用@Configuration,说明这也是springboot ioc容器的配置类。

其次@ComponentScan注解定义包扫描范围,所以启动类最后放在root package路径下。

最后最关键的注解@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
   String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    ......
}

从代码看出,这个注解通用@Import(…)这个注解来自动注入配置而其中AutoConfigurationImportSelector.class这个类就是springboot自动话配置的关键
先看图:
在这里插入图片描述
从这个图可以看出,@EnableAutoConfiguration类似八爪鱼一样,把所有的配置给集合到一起。
看AutoConfigurationImportSelector.class的源码:

首先看selectImports方法
AutoConfigurationImportSelector实现ImportSelector接口的selectImports,selectImports这个方法会放回一组路径,spring启动的时候会自动注入路径的配置类。大致在spring的ConfigurationClassParser$DeferredImportSelectorGroupingHandler类中的processImports()方法实现的。

public String[] selectImports(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
   }
   // 获取自动化配置元数据
   AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
         .loadMetadata(this.beanClassLoader);
   // 获取自动化配置列表(*)
   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
         annotationMetadata);
   // 返回配置类全路径名  spring会自动注入配置
   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

其中的getAutoConfigurationEntry:

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
                                             AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
   // 获取注释属性
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
   // 获取配置路径列表(*)
   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
   configurations = removeDuplicates(configurations);
   // 排除配置路径
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   checkExcludedClasses(configurations, exclusions);
   configurations.removeAll(exclusions);
   configurations = filter(configurations, autoConfigurationMetadata);
   fireAutoConfigurationImportEvents(configurations, exclusions);
   return new AutoConfigurationEntry(configurations, exclusions);
}

getCandidateConfigurations:

// 调用SpringFactoriesLoader对象 获取META-INF/spring.factories下面的配置(*)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
   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;
}

getSpringFactoriesLoaderFactoryClass:

// 获取EnableAutoConfiguration的class
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
   return EnableAutoConfiguration.class;
}

可以看出,我们通过getCandidateConfigurations方法获取配置,而这个方法最终调用的是SpringFactoriesLoader.loadFactoryNames方法获取配置类,我们需要两个参数,一个是EnableAutoConfiguration的class,一个是ClassLoader
SpringFactoriesLoader.loadFactoryNames:

// 通过class名字获取获取META-INF/spring.factories
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
   String factoryTypeName = factoryType.getName();
   return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

我们看一下META-INF/spring.factories
在这里插入图片描述
到这里,我们就大致知道getAutoConfigurationEntry自动化获取配置方法就是通过EnableAutoConfiguration的路径,通过SpringFactoriesLoader的loadFactoryNames方法获取自动化配置的左右类的路径列表。然后使用ImportSelector接口的selectImports方法返回需要自动配置的对象列表,然后通过spring的ConfigurationClassParser D e f e r r e d I m p o r t S e l e c t o r G r o u p i n g H a n d l e r 类 中 的 p r o c e s s I m p o r t s ( ) 方 法 来 自 动 注 入 所 有 需 要 自 动 化 配 置 的 类 。 C o n f i g u r a t i o n C l a s s P a r s e r DeferredImportSelectorGroupingHandler类中的processImports()方法来自动注入所有需要自动化配置的类。 ConfigurationClassParser DeferredImportSelectorGroupingHandlerprocessImports()ConfigurationClassParserDeferredImportSelectorGroupingHandler类中的processImports()方法:

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
                     Collection<SourceClass> importCandidates, boolean checkForCircularImports) {

   if (importCandidates.isEmpty()) {
      return;
   }

   if (checkForCircularImports && isChainedImportOnStack(configClass)) {
      this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
   }
   else {
      this.importStack.push(configClass);
      try {
         for (SourceClass candidate : importCandidates) {
            // 1、如果该配置类被ImportSelector修饰,则当成ImportSelector进行处理
            if (candidate.isAssignable(ImportSelector.class)) {
               // Candidate class is an ImportSelector -> delegate to it to determine imports
               Class<?> candidateClass = candidate.loadClass();
               ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
               ParserStrategyUtils.invokeAwareMethods(
                     selector, this.environment, this.resourceLoader, this.registry);
               if (selector instanceof DeferredImportSelector) {
                  this.deferredImportSelectorHandler.handle(
                        configClass, (DeferredImportSelector) selector);
               }
               else {
                  String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                  Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                  processImports(configClass, currentSourceClass, importSourceClasses, false);
               }
            }
            // 2、如果该配置类被ImportBeanDefinitionRegistrar修饰,则当成ImportBeanDefinitionRegistrar进行处理
            else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
               // Candidate class is an ImportBeanDefinitionRegistrar ->
               // delegate to it to register additional bean definitions
               Class<?> candidateClass = candidate.loadClass();
               ImportBeanDefinitionRegistrar registrar =
                     BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
               ParserStrategyUtils.invokeAwareMethods(
                     registrar, this.environment, this.resourceLoader, this.registry);
               configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
            }
            // 3、如果该配置类被Import修饰,则当成Import进行处理
            else {
               // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
               // process it as an @Configuration class
               this.importStack.registerImport(
                     currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
               processConfigurationClass(candidate.asConfigClass(configClass));
            }
         }
      }
      catch (BeanDefinitionStoreException ex) {
         throw ex;
      }
      catch (Throwable ex) {
         throw new BeanDefinitionStoreException(
               "Failed to process import candidates for configuration class [" +
                     configClass.getMetadata().getClassName() + "]", ex);
      }
      finally {
         this.importStack.pop();
      }
   }
}

注释源码:https://gitee.com/w849027724/spring-boot-master
链接:
https://juejin.im/post/5d63b455f265da03e52341d0
http://tengj.top/2017/03/09/springboot3/
https://www.jianshu.com/p/3da069bd865c

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值