SpringBoot的启动配置

引言:主要是为了个人学习,方便后期查看。

SpringBoot的入口

@SpringBootApplication
public class MallTany01Application {

    public static void main(String[] args) {
        SpringApplication.run(MallTany01Application.class, args);
    }
}

@SpringBootApplication注解标注主程序类,表明这是一个Spring Boot应用。

@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表明该类是springBoot的配置类。

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

其中包含@Configuration注解,@Configuration就是告诉SpringBoot这是一个配置类,相当于Spring中的xml配置文件。此外在@Configuration包含元注解@Component@Component他的作用就是给IOC容器添加组件 。

所以@SpringBootConfiguration注解的作用就是标识一个配置类,并且添加到IOC容器中。


@EnableAutoConfiguration为自动配置注解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
  • @AutoConfigurationPackage:自动配置包。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

其中@Import注解的作用为向容器中添加组件。接下来简单解释一下@Import注解。

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

   /**
    * {@link Configuration @Configuration}, {@link ImportSelector},
    * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
    */
   Class<?>[] value();

}

@Import可以传入 Configuration,ImportSelector,ImportBeanDefinitionRegistrar,regular component classes。此处的@Import传入的是实现了ImportBeanDefinitionRegistrar接口的类。

ImportBeanDefinitionRegistrar接口

public interface ImportBeanDefinitionRegistrar {

   /**
    * Register bean definitions as necessary based on the given annotation metadata of
    * the importing {@code @Configuration} class.
    * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
    * registered here, due to lifecycle constraints related to {@code @Configuration}
    * class processing.
    * <p>The default implementation delegates to
    * {@link #registerBeanDefinitions(AnnotationMetadata, BeanDefinitionRegistry)}.
    * @param importingClassMetadata annotation metadata of the importing class
    * @param registry current bean definition registry
    * @param importBeanNameGenerator the bean name generator strategy for imported beans:
    * {@link ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR} by default, or a
    * user-provided one if {@link ConfigurationClassPostProcessor#setBeanNameGenerator}
    * has been set. In the latter case, the passed-in strategy will be the same used for
    * component scanning in the containing application context (otherwise, the default
    * component-scan naming strategy is {@link AnnotationBeanNameGenerator#INSTANCE}).
    * @since 5.2
    * @see ConfigurationClassPostProcessor#IMPORT_BEAN_NAME_GENERATOR
    * @see ConfigurationClassPostProcessor#setBeanNameGenerator
    */
   default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
         BeanNameGenerator importBeanNameGenerator) {

      registerBeanDefinitions(importingClassMetadata, registry);
   }

   /**
    * Register bean definitions as necessary based on the given annotation metadata of
    * the importing {@code @Configuration} class.
    * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
    * registered here, due to lifecycle constraints related to {@code @Configuration}
    * class processing.
    * <p>The default implementation is empty.
    * @param importingClassMetadata annotation metadata of the importing class
    * @param registry current bean definition registry
    */
   default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   }

}

其中registerBeanDefinitions方法中包含有2个参数:

  • AnnotationMetadata:导入类的注解原信息

  • BeanDefinitionRegistry:注册当前bean。

    • BeanDefinitionRegistry接口存在

      void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;
      

      其中beanName:bean的名字。beanDefinition:bean的定义。

      在此处。beanDefinition是通过他的实现类GenericBeanDefinition来创建的


回到主题。@Import(AutoConfigurationPackages.Registrar.class)@Import 注解中放入的是AutoConfigurationPackages.Registrar.class

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
      register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
   }

   @Override
   public Set<Object> determineImports(AnnotationMetadata metadata) {
      return Collections.singleton(new PackageImports(metadata));
   }
}

Registrar类中可以看出,它继承了ImportBeanDefinitionRegistrar接口。实现了registerBeanDefinitions 方法。

其中 register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));

包含有2个参数

  • registry:BeanDefinitionRegistry,用来注册bean

  • new PackageImports(metadata).getPackageNames().toArray(new String[0])

    • private static final class PackageImports {
      
         private final List<String> packageNames;
      
         PackageImports(AnnotationMetadata metadata) {
            AnnotationAttributes attributes = AnnotationAttributes
                  .fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false));
            List<String> packageNames = new ArrayList<>();
            for (String basePackage : attributes.getStringArray("basePackages")) {
               packageNames.add(basePackage);
            }
            for (Class<?> basePackageClass : attributes.getClassArray("basePackageClasses")) {
               packageNames.add(basePackageClass.getPackage().getName());
            }
           //packageNames初始时为空。
            if (packageNames.isEmpty()) {
               packageNames.add(ClassUtils.getPackageName(metadata.getClassName()));
            }
            this.packageNames = Collections.unmodifiableList(packageNames);
         }
      

      packageNames.add(ClassUtils.getPackageName(metadata.getClassName()));其中 metadata.getClassName()使用的AnnotationMetadata 接口实现类StandardAnnotationMetadata下的getclassName()方法 。

      @Override
      public String getClassName() {
         return this.introspectedClass.getName();
      }
      
      private final Class<?> introspectedClass;
      

      所以metadata.getClassName()得到是introspectedClass。也就是标注注解的原始类。实验中MallTany01Application的全类名为class com.zwd.mall.tany01.MallTany01Application

      因此this.packageNamescom.zwd.mall.tany01


      register(registry, com.zwd.mall.tany01);

      public static void register(BeanDefinitionRegistry registry, String... packageNames) {
        //是否包含org.springframework.boot.autoconfigure.AutoConfigurationPackages,初始时不包含
         if (registry.containsBeanDefinition(BEAN)) {
            BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
            ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();
            constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));
         }
         else {
           //new了一个BeanDefinitionRegistry接口的实现类,利用该实现类来定义bean
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClass(BasePackages.class);
            beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
            beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
           //注册com.zwd.mall.tany01下的bean
            registry.registerBeanDefinition(BEAN, beanDefinition);
         }
      }
      

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

    @Import(AutoConfigurationImportSelector.class)此处导入了AutoConfigurationImportSelector

    public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
          ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    

其中public interface DeferredImportSelector extends ImportSelector {}

在前面@Inport中就可以传入实现了ImportSelector 接口的类

public interface ImportSelector {

   /**
    * Select and return the names of which class(es) should be imported based on
    * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
    * @return the class names, or an empty array if none
    */
  
   String[] selectImports(AnnotationMetadata importingClassMetadata);

   /**
    * Return a predicate for excluding classes from the import candidates, to be
    * transitively applied to all classes found through this selector's imports.
    * <p>If this predicate returns {@code true} for a given fully-qualified
    * class name, said class will not be considered as an imported configuration
    * class, bypassing class file loading as well as metadata introspection.
    * @return the filter predicate for fully-qualified candidate class names
    * of transitively imported configuration classes, or {@code null} if none
    * @since 5.2.4
    */
   @Nullable
   default Predicate<String> getExclusionFilter() {
      return null;
   }

}

selectImports方法返回一个字符串数组。返回的是要导入类的名称。

AnnotationMetadata:当前标注Import注解的所有信息。

所以在类AutoConfigurationImportSelector中我们定位到 selectImports方法

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
   }
   AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
  //返回到导入的类的名称
   return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);方法

protected AutoConfigurationEntry getAutoConfigurationEntry(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 = getConfigurationClassFilter().filter(configurations);
   fireAutoConfigurationImportEvents(configurations, exclusions);
   return new AutoConfigurationEntry(configurations, exclusions);
}

List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);

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;
}
SpringFactoriesLoader.loadFactoryNames(
interface org.springframework.boot.autoconfigure.EnableAutoConfiguration,
类加载器);
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
  //工厂名:org.springframework.boot.autoconfigure.EnableAutoConfiguration
   String factoryTypeName = factoryType.getName();
  //加载spring工厂
   return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
   MultiValueMap<String, String> result = cache.get(classLoader);
   if (result != null) {
      return result;
   }

   try {
     //FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"
      Enumeration<URL> urls = (classLoader != null ?
            classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
            ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
      result = new LinkedMultiValueMap<>();
      while (urls.hasMoreElements()) {
         URL url = urls.nextElement();
         UrlResource resource = new UrlResource(url);
        //加载所有META-INF/spring.factories下的自动配置文件
         Properties properties = PropertiesLoaderUtils.loadProperties(resource);
         for (Map.Entry<?, ?> entry : properties.entrySet()) {
            String factoryTypeName = ((String) entry.getKey()).trim();
            for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
               result.add(factoryTypeName, factoryImplementationName.trim());
            }
         }
      }
      cache.put(classLoader, result);
      return result;
   }
   catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load factories from location [" +
            FACTORIES_RESOURCE_LOCATION + "]", ex);
   }
}

下图列出的是

jar:file:/D:/InstallationPath/m2/repository/org/springframework/boot/spring-boot/2.3.4.RELEASE/spring-boot-2.3.4.RELEASE.jar!/META-INF/spring.factories下的配置类

在这里插入图片描述

所有spring.factories下的配置类

在这里插入图片描述

最后在得到的result中找到前缀为org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置类

这样就完成了初始化自动配置加载。


总结

  1. @AutoConfigurationPackage:加载主程序入口所在包下的所有组件
  2. @Import(AutoConfigurationImportSelector.class):将/META-INF/spring.factories中所有前缀为org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置进行加载。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值