@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
除去上面四个元注解外,我们主要关注下面三个注解。
1、@SpringBootConfiguration
继续往里看
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
我们发现这个注解只是代表当前是一个配置类
2、@EnableAutoConfiguration
往里看
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration
依旧是一个组合注解
2.1、@AutoConfigurationPackage
继续往里看
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage
发现它通过@Import注解给容器中添加了Registrar组件,继续查看这个组件
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}
它通过实现ImportBeanDefinitionRegistrar中的registerBeanDefinitions方法来导入一系列组件
其中参数metadata为@SpringBootApplication注解标注的元信息
这个方法的内容不难看出是得到@SpringBootApplication的包路径名,将其路径下的所有组件注册到容器中
通过debug模式下选中
(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames()
ctrl+u再执行我们可以看出它得到的就是启动类所在的路径
因此@AutoConfigurationPackage就是扫描启动类所在的路径下的所有组件添加到spring容器中
2.2、@Import({AutoConfigurationImportSelector.class})
往里走
收首先我们看到selectImports方法,重点在下面这行代码
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
随后找到getAutoConfigurationEntry的实现,重点在下面这些代码
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
不难看出其实主要在第二行获取configurations这个list,后续都是在对这个list做删减操作
因此我们继续进入getCandidateConfigurations方法内部
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
我们发现是从this.getSpringFactoriesLoaderFactoryClass()来获得所有组件
随后我们点击下面的EnableAutoConfiguration.class会发现
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
是从这个包下读取所有组件
根据下面的assert断言提示信息找到该包下的META-INF/srping.factories
我们会发现这下面会有很多的组件
因此@Import({AutoConfigurationImportSelector.class})是导入spring提供给我们的组件,但是这个是按需导入的,因为大部分组件都是通过@Conditonal来导入,当我们没有导入对应的依赖包时,虽然这些组件都会全部加载,但最终只会按需配置。
3、@ComponentScan
指定扫描哪些注解