SpringBoot会将所有的功能场景都封装成一个一个的启动器,供开发人员使用。
我们在使用的时候也可以直接去官网上找我们所需的启动器,直接将其引入。
获取启动器文档:
主程序(重要)
//@SpringBootApplication 标注,是一个SpringBoot应用 @SpringBootApplication public class SpringbootdemoApplication { public static void main(String[] args) { SpringApplication.run(SpringbootdemoApplication.class, args); } }
再写SpringBoot项目的时候,总要写这么一个主程序,这个主程序最大的特点就是其类上放了一个@SpringBootApplication注解,这也正是SpringBoot项目启动的核心,也是我们要研究的重点。
注意:之后的分析可能会深入源码,源码是一层一层嵌套的,所以光靠文字说明会比较难以理解,最好是自己在IDE环境下跟着一步一步跟着点下去。当然也可以绕过这一部分直接看结论。
点开@SpringBootApplication,可以发现它是一个组合注解,主要是由这么几个注解构成的。
@SpringBootConfiguration//核心 @EnableAutoConfiguration//核心 @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
我们首先要研究的就是核心的两个注解 @SpringBootConfiguration和@EnableAutoConfiguration,逐个进行分析。
@SpringBootConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { }
可以看到SpringBootConfiguration其实就携带了一个@Configuration注解,这个注解我们再熟悉不过了,他就代表自己是一个Spring的配置类。所以我们可以认为:
@SpringBootConfiguration = @Configuration
@EnableAutoConfiguration
顾名思义,这个注解一定和自动配置相关,点进去看源代码之后可以发现,其内部就包含了这么两个注解。
@AutoConfigurationPackage //自动配置包 @Import(AutoConfigurationImportSelector.class)//自动配置导入选择
来看看@Import(AutoConfigurationImportSelector.class)
中的内容:
它帮我们导入了AutoConfigurationImportSelector,这个类中存在一个方法可以帮我们获取所有的配置,代码如下。
/* 所有的配置都存放在configurations中, 而这些配置都从getCandidateConfiguration中获取, 这个方法是用来获取候选的配置。 */ List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
getCandidateConfigurations():
这个方法可以用来获取所有候选的配置,那么这些候选的配置又是从哪来的呢?
/*获取候选的配置*/ protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), 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; }
实际上它返回了一个List,这个List是由loadFactoryNames()方法返回的,其中传入了一个getSpringFactoriesLoaderFactoryClass(),我们可以看看这个方法的内容。
protected Class<?> getSpringFactoriesLoaderFactoryClass() { return EnableAutoConfiguration.class; }
我们看到了一个眼熟的词 —— EnableAutoConfiguration,也就是说,它实际上返回的就是标注了这个类的所有包。标注了这个类的包不就是@SpringBootApplication
吗?
所以我们可以得出结论:它兜兜转转绕了这么多地方,就是为了将启动类所需的所有资源导入。
我们接着往下看,它其中还有这么一条语句,是一条断言:
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.");
这个断言的意思是,configurations必须非空,否则就打印一段话,No auto configuration classes found in META-INF/spring.factories
,我们把这个逻辑反过来想想。如果这个集合不为空,是不是就代表找到了这个spring.factories并且会去加载这个文件中的内容呢?
带着这个疑问,我们首先找到spring.factories这个文件:
可以看到里面包含了很多自动配置属性:
我们可以随便找一个自动配置点进去,比如WebMvcAutoConfiguration
:
这里放了所有关于WebMvc的配置,如视图解析器、国际化等等。
分析到这里,我们就可以得出一个完整的结论了:
当我们的SpringBoot项目启动的时候,会先导入AutoConfigurationImportSelector,这个类会帮我们选择所有候选的配置,我们需要导入的配置都是SpringBoot帮我们写好的一个一个的配置类,那么这些配置类的位置,存在与META-INF/spring.factories文件中,通过这个文件,Spring可以找到这些配置类的位置,于是去加载其中的配置。