SpringBoot系列:自动配置源码分析

源码分析

@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
由springboot定义,标注一个springboot配置类,配置类相当于配置文件,是容器中的一个组件.
而@SpringBootConfiguration的注解@Configuration是由spring定义.

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

@EnableAutoConfiguration
开启自动配置功能
被@AutoConfigurationPackage(自动配置包)标注,
被@import(EnableAutoConfigurationImportSelector.class)标注

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

EnableAutoConfigurationImportSelector.class是决定导入哪些组件的选择器,父类AutoConfigurationImportSelector.class的public String[] selectImports(AnnotationMetadata annotationMetadata)方法将需要的组件以全类名的String[]的方式返回,添加到容器中,会给容器导入很多自动配置类(xxxAutoConfiguration,位于spring-boot-autoconfigure.jar),作用是导入这个功能场景需要的所有组件并配置好,免去了手动编写配置注入功能组件

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

得到这个String[]的方法是getCandidateConfigurations(annotationMetadata, attributes),内部调用SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()),
第一个参数getSpringFactoriesLoaderFactoryClass()即EnableAutoConfiguration.class.

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

loadFactoryNames方法

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
   String factoryClassName = factoryClass.getName();
   try {
      Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
            ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
      List<String> result = new ArrayList<String>();
      while (urls.hasMoreElements()) {
         URL url = urls.nextElement();
         Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
         String factoryClassNames = properties.getProperty(factoryClassName);
         result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
      }
      return result;
   }
   catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
            "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
   }
}

通过类加载器的getResources方法(参数为"META-INF/spring.factories")从类路径下的META-INF/spring.factories获取EnableAutoConfiguration指定的值,这些值作为自动配置类导入到容器中.

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

@AutoConfigurationPackage又被@import(spring的底层注解,给容器中导入一个组件,由括起的AutoConfigurationPackages.Registrar.class来决定导入的组件)标注.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}

new PackageImport(metadata).getPackageName()所代表的即是被@SpringBootApplication标注的主配置类所在的包,意味着将及其子包内的所有组件都扫描到spring容器中.

@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata,BeanDefinitionRegistry registry) {
      register(registry, new PackageImport(metadata).getPackageName());
   }
}

总结:

  1. @SpringBootConfiguration将启动类标注为一个组件
  2. @EnableAutoConfiguration开启了自动配置功能
    其中:
    2.1 @AutoConfigurationPackage是扫描启动类的包及其子包的组件,进行自动配置
    2.2 @import(EnableAutoConfigurationImportSelector.class)是按照功能场景的需求添加springboot自身的组件,进行自动配置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值