1. 文章引言
先看看SpringBoot
的主配置类:
/**
* @author super先生
* @datetime 2022/8/5 15:16
* @desc superjson框架的启动类
*/
@SpringBootApplication
@Slf4j
public class SuperJsonManagerApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run =
SpringApplication.run(SuperJsonManagerApplication.class, args);
}
}
main
方法运行了一个run()
方法,在run
方法中必须要传入一个被@SpringBootApplication
注解的类。
SpringBoot
应用标注在某个类上说明这个类是SpringBoot
的主配置类,SpringBoot
就会运行这个类的main
方法来启动SpringBoot
项目。
2. @SpringBootApplication
那@SpringBootApplication
注解到底是什么呢?点进去看看发现@SpringBootApplication
是一个组合注解,如下图所示:
2.1 @SpringBootConfiguration
先看看@SpringBootConfiguration
注解:
这个注解很简单,表明该类是一个Spring
的配置类,再进去看看@Configuration
:
说明Spring的
配置类也是Spring
的一个组件。
2.2 @EnableAutoConfiguration
这个注解是开启自动配置的功能。
- 看看
@AutoConfigurationPackage
注解:
这个注解是自动配置包,主要是使用的@Import
来给Spring
容器中导入一个组件 ,这里导入的是Registrar.class
,如下图所示:
就是通过这个方法获取扫描的包路径,在如下行代码上打一断点,debug
看看:
启动项目后进入断点,已经获取到了包路径,如下图所示:
注意断点出的metadata(元空间)
,这是什么呢?可以看到是标注在@SpringBootApplication
注解上的SuperJsonManagerApplication
,也就是我们的主配置类:
说白了就是将主配置类(即@SpringBootApplication
标注的类)的所在包及子包里面所有组件扫描加载到Spring容器。所以包名一定要注意。
@Import({AutoConfigurationImportSelector.class})
现在包扫描路径获取到了,那具体加载哪些组件呢,看看这个注解:@Import({AutoConfigurationImportSelector.class})
@Import
注解就是给Spring
容器中导入一些组件,这里传入了一个组件的选择器:AutoConfigurationImportSelector
。
里面有一个selectImports
方法,将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中:
因为我的spring boot
版本为2.5.0
,有的版本的代码可能如下这样:
但这不影响使用,只是版本不同,核心代码都一样。
debug
运行时可以看到,它给容器中导入非常多的自动配置类(xxxAutoConfiguration
),就是给容器中导入这个场景需要的所有组件,并配置好这些组件,如下图所示:
有了自动配置类,免去了我们手动编写配置注入功能组件等的工作。
那他是如何获取到这些配置类的呢,点击getAutoConfigurationEntry(annotationMetadata)
进入该方法,然后再进入getCandidateConfigurations(annotationMetadata, attributes)
方法,可以看到如下图所示的方法:
点击loadFactoryNames
进入该方法后,再点击进入loadSpringFactories
方法,如下图所示:
loadFactoryNames
会从META-INF/spring.factories
中获取资源,然后通过Properties
加载资源。
3. 总结
Spring Boot
在启动的时候从类路径下的META-INF/spring.factories
中获取EnableAutoConfiguration
指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。以前我们需要自己配置的东西,自动配置类都帮我们完成了。
比如看看WebMvcAutoConfiguration
,都已经帮我们配置好了,我们不用再单独配置了: