相信小伙伴们在写springboot项目的时候,在启动类上加上@SpringBootApplication注解引导,就能够自动装配。例以下面这样:java
@SpringBootApplication
public class SpringbootTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTestApplication.class, args);
}
}
复制代码
引用官方的话:@SpringBootApplication被用于激活@EnableAutoConfiguration
、@ComponentScan
和@Configuration
三个特性。其中,@EnableAutoConfiguration
负责激活SpringBoot自动装配机制,@ComponentScan
激活@Component的扫描,@Configuration
声明被标注为配置类。官方文档继续告诉开发人员@SpringBootApplication注解等同于@Configuration
、@EnableAutoConfiguraion
和@ComponentScan
注解,且它们均使用默认属性。咱们这样改造上面的代码:spring
//@SpringBootApplication
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class SpringbootTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootTestApplication.class, args);
}
}
复制代码
咱们启动运行,观察日志,没错,一切正如你想象的正常。springboot
额~ 相信有很多人翻过springBoot2.x的@SpringBootApplication的源码,发现是下面这样的:ide
@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 {
....
}
复制代码
因而可知,那么有个疑问?@SpringBootSpplication是否是不等价上面介绍的@EnableAutoConfiguration
、@ComponentScan
和@Configuration
注解?this
那么咱们分析,由上可见,@SpringBootApplication等价于@SpringBootConfiguration
、@ComponentScan
和@EnableAutoConfiguration
,不过@ComponentScan并不是使用了默认值,而是添加了排除的TypeFilter实现:TypeExcludeFilter和AutoConfigurationExcludeFilter。前者由Springboot1.4引入,用于查找BeanFactory中已注册的TypeExcludeFilter Bean,做为代理执行对象:spa
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一般不会表现出与文档相异的行为,但官方没更新文档也没给出具体有什么不同的解释。code
但咱们知道,从SpringBoot1.4开始,@SpringBootApplication注解再也不标注@Configuration,而是@SpringBootConfiguration
,不过二者在运行上的行为并无什么不同,这种相似于对象之间的继承关系,咱们称之为“多层次 @Component‘派生性’”
,哈哈哈,而且这种能力也容许咱们扩展使用的,是否是很嗨。咱们看下@Configuration注解,它其实标注了@Component注解: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 {
}
复制代码
所以三者的关系为:
咱们知道,@CompoentScan仅扫描带有@Component注解的类,并注册成bean,然而因为@SpringBootConfiguration属于多层次的@Component“派生”注解,因此能被@CompoentScan识别。可是咱们知道@CompoentScan属于Spring Framework,而@SpringBootConfiguration来自SpringBoot,那么是什么机制让@CompoentScan可以识别@SpringBootConfiguration注解呢?这种机制就是前面提到的“多层次 @Component ‘派生性’”。
SpringBoot是经过注解@EnableAutoConfiguration的方式,去查找,过滤,加载所需的Configuration,@ComponentScan扫描咱们自定义的bean,@SpringBootConfiguration(派生性@Component)使得被@SpringBootApplication注解的类声明为注解类,所以@SpringBootApplication的做用等价于同时组合使用@EnableAutoConfiguration,@ComponentScan,@SpringBootConfiguration。