简介
方法步骤
1. SpringBoot启动主程序类:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
每次我们直接直接启动这个启动类,SpringBoot就启动成功了,并且帮我们配置了好多自动配置类。
其中最重要是 @SpringBootApplication 这个注解,我们点进去看一下。
2. 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 {
三个比较重要的注解:
- @SpringBootConfiguration : Spring Boot的配置类,标注在某个类上,表示这是一个Spring Boot的配置类
- @EnableAutoConfiguration: 开启自动配置类,SpringBoot的精华所在。
- @ComponentScan包扫描
以前我们需要配置的东西,Spring Boot帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;
3. EnableAutoConfiguration注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
两个比较重要的注解:
- @AutoConfigurationPackage:自动配置包
- @Import: 导入自动配置的组件
4. AutoConfigurationPackage注解:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
它其实是注册了一个Bean的定义。
new PackageImport(metadata).getPackageName(),它其实返回了当前主程序类的 同级以及子级 的包组件。
以上图为例,DemoApplication是和demo包同级,但是demo2这个类是DemoApplication的父级,和example包同级
也就是说,DemoApplication启动加载的Bean中,并不会加载demo2,这也就是为什么,我们要把DemoApplication放在项目的最高级中。
5. Import(AutoConfigurationImportSelector.class)注解:
可以从图中看出 AutoConfigurationImportSelector 继承了 DeferredImportSelector 继承了 ImportSelector
AutoConfigurationImportSelector 重写ImportSelector的方法:selectImports。
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
可以看到这行:
List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);
它其实是去加载 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";外部文件。这个外部文件,有很多自动配置的类。如下:
总结:
- 流程图:
Springboot启动的时候,会通过Main方法的启动类的 @SpringBootApplication注解,找到 内包含的@EnableAutoConfiguration注解来开启自动配置,
@EnableAutoConfiguration中包含的主要注解
- @AutoConfigurationPackage
- @Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage会返回主程序类的同级以及子级的包组件,@Import(AutoConfigurationImportSelector.class)中的AutoConfigurationImportSelector 方法中的selectImports它会去加载spring.factories外部文件,这个外部文件有很多的自动配置类。
参考资料 & 致谢
【1】Spring技术内幕:深入解析Spring架构与设计原理(第2版)