乐趣区

关于java:SpringBoot进阶之道SpringBootApplication

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

@SpringBootApplication
public 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
@ComponentScan
public 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
@ComponentScan
public @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
@Component
public @interface Configuration {...}

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

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @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。

退出移动版