置信小伙伴们在写springboot我的项目的时候,在启动类上加上@SpringBootApplication注解疏导,就能够主动拆卸。例如上面这样:

@SpringBootApplicationpublic class SpringbootTestApplication {    public static void main(String[] args) {        SpringApplication.run(SpringbootTestApplication.class, args);    }}
  • 那么@SpringBootApplication注解是怎么做到的?
  • 什么叫 @Component派生注解

1、了解@SpringBootApplication语义

援用官网的话:@SpringBootApplication被用于激活@EnableAutoConfiguration@ComponentScan@Configuration三个个性。其中,@EnableAutoConfiguration负责激活SpringBoot主动拆卸机制,@ComponentScan激活@Component的扫描,@Configuration申明被标注为配置类。官网文档持续通知开发人员@SpringBootApplication注解等同于@Configuration@EnableAutoConfiguraion@ComponentScan注解,且它们均应用默认属性。咱们这样革新下面的代码:

//@SpringBootApplication@Configuration@EnableAutoConfiguration@ComponentScanpublic class SpringbootTestApplication {    public static void main(String[] args) {        SpringApplication.run(SpringbootTestApplication.class, args);    }}

咱们启动运行,察看日志,没错,所有正如你设想的失常。

额~ 置信有不少人翻过springBoot2.x的@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 {    ....}

由此可见,那么有个疑难?@SpringBootApplication是不是不等价下面介绍的@EnableAutoConfiguration@ComponentScan@Configuration注解?

那么咱们剖析,由上可见,@SpringBootApplication等价于@SpringBootConfiguration@ComponentScan@EnableAutoConfiguration,不过@ComponentScan并非应用了默认值,而是增加了排除的TypeFilter实现:TypeExcludeFilter和AutoConfigurationExcludeFilter。前者由Springboot1.4引入,用于查找BeanFactory中已注册的TypeExcludeFilter Bean,作为代理执行对象:

public class TypeExcludeFilter implements TypeFilter, BeanFactoryAware {        ...    @Override    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {        if (this.beanFactory instanceof ListableBeanFactory && this.getClass() == TypeExcludeFilter.class) {            Collection<TypeExcludeFilter> delegates = ((ListableBeanFactory)this.beanFactory).getBeansOfType(TypeExcludeFilter.class).values();            Iterator var4 = delegates.iterator();            while(var4.hasNext()) {                TypeExcludeFilter delegate = (TypeExcludeFilter)var4.next();                if (delegate.match(metadataReader, metadataReaderFactory)) {                    return true;                }            }        }        return false;    }        ...}

而后者从SpringBoot1.5开始反对,用于排除其余同时标注@Configuration和@EnableAutoConfiguration的类:

public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoaderAware {        ...    @Override    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {        return this.isConfiguration(metadataReader) && this.isAutoConfiguration(metadataReader);    }    private boolean isConfiguration(MetadataReader metadataReader) {        return metadataReader.getAnnotationMetadata().isAnnotated(Configuration.class.getName());    }    private boolean isAutoConfiguration(MetadataReader metadataReader) {        return this.getAutoConfigurations().contains(metadataReader.getClassMetadata().getClassName());    }    protected List<String> getAutoConfigurations() {        if (this.autoConfigurations == null) {            this.autoConfigurations = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, this.beanClassLoader);        }        return this.autoConfigurations;    }}

咱们来比照一下SpringBoot1.3.8的@SpringBootApplication的申明:

@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Configuration和@EnableAutoConfiguration@ComponentScanpublic @interface SpringBootApplication {    ....}

由此可见,SpringBoot1.3.8的实现与官网文档形容的是一样的。只管SpringBoot1.4之后的@SpringBootApplication通常不会体现出与文档相异的行为,但官网没更新文档也没给出具体有什么不一样的解释。

2、@Component ‘派生性’

但咱们晓得,从SpringBoot1.4开始,@SpringBootApplication注解不再标注@Configuration,而是@SpringBootConfiguration,不过两者在运行上的行为并没有什么不一样,这种相似于对象之间的继承关系,咱们称之为“多层次 @Component‘派生性’”,哈哈哈,并且这种能力也容许咱们扩大应用的,是不是很嗨。咱们看下@Configuration注解,它其实标注了@Component注解:

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

所以咱们得悉,@Configuration实际上是@Component的派生性注解,同理@SpringBootConfiguration标注了@Configuration:

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

因而三者的关系为:

  • @component

    • @Configuration

      • @SpringBootConfiguration

咱们晓得,@CompoentScan仅扫描带有@Component注解的类,并注册成bean,然而因为@SpringBootConfiguration属于多层次的@Component“派生”注解,所以能被@CompoentScan辨认。然而咱们晓得@CompoentScan属于Spring Framework,而@SpringBootConfiguration来自SpringBoot,那么是什么机制让@CompoentScan可能辨认@SpringBootConfiguration注解呢?这种机制就是后面提到的“多层次 @Component ‘派生性’”。

3、小结

SpringBoot是通过注解@EnableAutoConfiguration的形式,去查找,过滤,加载所需的Configuration,@ComponentScan扫描咱们自定义的bean,@SpringBootConfiguration(派生性@Component)使得被@SpringBootApplication注解的类申明为注解类,因而@SpringBootApplication的作用等价于同时组合应用@EnableAutoConfiguration,@ComponentScan,@SpringBootConfiguration。