置信小伙伴们在写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。