美文网首页SpringBoot系列
2) SpringBootApplication注解详解

2) SpringBootApplication注解详解

作者: 涣涣虚心0215 | 来源:发表于2021-02-20 16:34 被阅读0次

@SpringbootConfiguration

@SpringbootConfiguration注解等同于以下下三个注解:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan
@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 {

    /**
     * Exclude specific auto-configuration classes such that they will never be applied.
     * @return the classes to exclude
     */
    @AliasFor(annotation = EnableAutoConfiguration.class)
    Class<?>[] exclude() default {};

    /**
     * Exclude specific auto-configuration class names such that they will never be
     * applied.
     * @return the class names to exclude
     * @since 1.3.0
     */
    @AliasFor(annotation = EnableAutoConfiguration.class)
    String[] excludeName() default {};

    /**
     * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
     * for a type-safe alternative to String-based package names.
     * @return base packages to scan
     * @since 1.3.0
     */
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    /**
     * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to
     * scan for annotated components. The package of each class specified will be scanned.
     * <p>
     * Consider creating a special no-op marker class or interface in each package that
     * serves no purpose other than being referenced by this attribute.
     * @return base packages to scan
     * @since 1.3.0
     */
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

}

@SpringBootConfiguration

可以看到SpringBootConfiguration 等同于使用了@Configuration

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

}

@EnableAutoConfiguration

@EnableAutoConfiguration会根据classpath以及定义的Bean来帮你加载你想要的bean。
可以通过spring.autoconfigure.exclude来排除掉不想自动加载的bean。
且Auto-configuration发生在自定义的bean都被注册好了之后。
另外最好将带有@EnableAutoConfiguration的类放在root package,这样就能扫描所有子包下面的类。
auto-configuration的bean大多数都是带有@ConditionalOnClass and @ConditionalOnMissingBean 注解的bean。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
}
AutoConfigurationImportSelector

这个类实现了DeferredImportSelector被import进来,内部会调用getCandidateConfigurations()来加载所有的auto-configuration beans

//首先会从spring-boot-autoconfigure的jar文件里的META-INF/spring-autoconfigure-metadata.properties里面找到配置并组装成AutoConfigurationMetadata
protected AutoConfigurationEntry getAutoConfigurationEntry(
        AutoConfigurationMetadata autoConfigurationMetadata,
        AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    //获得注解的属性
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    //调用getCandidateConfigurations来获取classpath中存在的auto-configure beans
    List<String> configurations = getCandidateConfigurations(annotationMetadata,
            attributes);
    //去除重复的
    configurations = removeDuplicates(configurations);
    //根据exclude来剔除不需要的
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    //再根据AutoConfigurationMetadata来进行filter
    configurations = filter(configurations, autoConfigurationMetadata);
    //触发auto-configureimport的事件
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
        AnnotationAttributes attributes) {
    //内部还是通过SpringFactoriesLoader.loadFactoryNames
    // 来加载org.springframework.boot.autoconfigure.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;
}

从下面图中能看到SpringFactoriesLoader从spring.factory里找到207个auto-configuration的beans。

auto-configuration

AutoConfigurationImportSelector核心功能就是获取spring.factories中EnableAutoConfiguration所对应的Configuration类列表,由@EnableAutoConfiguration注解中的exclude/excludeName参数筛选一遍,再由AutoConfigurationImportFilter类所有实例筛选一遍,得到最终的用于Import的configuration和exclusion。
该函数是被谁调用的呢?在org.springframework.context.annotation.ConfigurationClassParser类中被processImports()调用,而processImports()函数被doProcessConfigurationClass()调用。
关于ConfigurationClassParser请参考Spring Annotation IOC

@ComponentScan

指定扫描basePackages的路径,具体可以查看@Configuration的javadoc文档。

相关文章

网友评论

    本文标题:2) SpringBootApplication注解详解

    本文链接:https://www.haomeiwen.com/subject/wbvexltx.html