SpringBootApplication注解


本文章仅用于本人学习笔记记录
来源《SpringBoot 源码解读与原理分析》
微信:A20991212A(如本文档内容侵权了您的权益,请您通过微信联系到我)

@SpringBootApplication

启动类上@SpringBootApplication注解源码

/**
 * ......
 * @since 1.2.0
 */
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication

文档注释原文翻译:

Indicates a configuration class that declares one or more @Bean methods and also triggers auto-configuration and component scanning. This is a convenience annotation that is equivalent to declaring
@Configuration, @EnableAutoConfiguration and @ComponentScan.
标识了一个配置类,这个配置类上声明了一个或多个 @Bean 的方法,并且它会触发自动配置和组件扫描。
这是一个很方便的注解,它等价于同时标注 @Configuration + @EnableAutoConfiguration + @ComponentScan 。

@ComponentScan

在SpringFramework中@ComponentScan可以指定包扫描的根路径,让 SpringFramework 来扫描指定包及子包下的组件,也可以不指定路径,默认扫描当前配置类所在包及子包里的所有组件(其实这就解释了为什么 SpringBoot 的启动类要放到所有类所在包的最外层)

@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

声明中有显式的指定了两个过滤条件

TypeExcludeFilter

向IOC容器中注册一些自定义的组件过滤器,以在包扫描的过程中过滤它们。

这种Filter的核心方法是 match 方法,它实现了过滤的判断逻辑:

public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
        throws IOException {
    if (this.beanFactory instanceof ListableBeanFactory && getClass() == TypeExcludeFilter.class) {
        Collection<TypeExcludeFilter> delegates = ((ListableBeanFactory) this.beanFactory)
                .getBeansOfType(TypeExcludeFilter.class).values();
        for (TypeExcludeFilter delegate : delegates) {
            if (delegate.match(metadataReader, metadataReaderFactory)) {
                return true;
            }
        }
    }
    return false;
}

从 BeanFactory (可以暂时理解成IOC容器)中获取所有类型为 TypeExcludeFilter 的组件,去执行自定义的过滤方法。

由此可见,TypeExcludeFilter 的作用是做扩展的组件过滤。

AutoConfigurationExcludeFilter

注解源码:

public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
        throws IOException {
    return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader);
}

private boolean isConfiguration(MetadataReader metadataReader) {
    return metadataReader.getAnnotationMetadata().isAnnotated(Configuration.class.getName());
}

private boolean isAutoConfiguration(MetadataReader metadataReader) {
    return getAutoConfigurations().contains(metadataReader.getClassMetadata().getClassName());
}

protected List<String> getAutoConfigurations() {
    if (this.autoConfigurations == null) {
        this.autoConfigurations = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,
                this.beanClassLoader);
    }
    return this.autoConfigurations;
}

match 方法要判断两个部分:是否是一个配置类,是否是一个自动配置类。

@SpringBootConfiguration

@Configuration
public @interface SpringBootConfiguration

文档注释原文翻译:

Indicates that a class provides Spring Boot application @Configuration . Can be used as an alternative to the Spring’s standard @Configuration annotation so that configuration can be found automatically (for example in tests).
Application should only ever include one @SpringBootConfiguration and most idiomatic Spring Boot applications will inherit it from @SpringBootApplication.
标识一个类作为 SpringBoot 的配置类,它可以是Spring原生的 @Configuration 的一种替换方案,目的是这个配置可以被自动发现。
应用应当只在主启动类上标注 @SpringBootConfiguration,大多数情况下都是直接使用 @SpringBootApplication。

它被 @Configuration 标注,说明它实际上是标注配置类的,而且是标注主启动类的。

@Configuration的作用

被 @Configuration 标注的类,会被 Spring 的IOC容器认定为配置类。

一个被 @Configuration 标注的类,相当于一个 applicationContext.xml 的配置文件。

例如:声明一个类,并标注 @Configuration 注解:

@Configuration
public class ConfigurationDemo {
    @Bean
    public Date currentDate() {
        return new Date();
    }
}

上述注册Bean的方式类比于xml:

<bean id="currentDate" class="java.util.Date"/>

之后使用注解启动方式,初始化一个IOC容器,并打印IOC容器中的所有bean的name:

public class MainApp {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigurationDemo.class);
        String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
        Stream.of(beanDefinitionNames).forEach(System.out::println);
    }
}

输出结果:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
configurationDemo
currentDate

可以发现组件,以及配置类本身被成功加载。

总结

  1. @SpringBootApplication 是组合注解。@SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan
  2. @ComponentScan 默认扫描当前配置类所在包及子包下的所有组件,提供TypeExcludeFilter和AutoConfigurationExcludeFilter。
  3. @SpringBootConfiguration 可标注配置类,@SpringBootConfiguration 并没有对@Configuration做实质性扩展。

文章作者: Adbo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Adbo !
评论
  目录