本文最后更新于 2025-03-27T01:25:37+08:00
启动入口及其注解说明
1 2 3 4 5 6 7
| @SpringBootApplication public class SummaryApplication { public static void main(String[] args) { SpringApplication.run(SummaryApplication.class, args); 也可简化调用静态方法 } }
|
通过源码发现该注解
- @Configuration
- @EnableAutoConfiguration
- @ComponentScan
三个注解的组合,这是在springboot 1.5以后为这三个注解做的一个简写。接下来简单说下这三个注解的功能:
1 2 3 4 5 6 7
| @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan public @interface SpringBootApplication { ... }
|
可见,其中最关键的就是@EnableAutoConfiguration
,我们详细说明一个这个组件:
1 2 3 4 5 6
| @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {
}
|
该注解也是一个合成注解,由 @AutoConfigurationPackage
和 @Import(AutoConfigurationImportSelector.class)
构成,其中 :
- @AutoConfigurationPackage : 启动时,向
AutoConfigurationPackage
组件中保存一些包路径,方便以后使用。
- @Import(AutoConfigurationImportSelector.class) : ==该注解也是本次讲解的重点,其目的是将项目以及依赖包下 所有符合条件的
@Configuuration
配置全部进行加载==。
总结一下:
和我们最想相关的几个组件,其中: ComponentScan用于扫描我们项目中写的@Component等Bean。但是有些Bean我们是自己在配置类中写的呀,该怎么加载进Spring呢?那就用到了AutoConfigurationImportSelector,它将本项目及其依赖中符合条件的配置类(Spring中大量使用到Codition*注解标注哪些条件下加载我们的配置信息,这就是SPI机制 )加载进Spring管理,这样手动注入的Bean,也就能让Spring识别啦。可这时,我们的项目本身就不到,不想自己再写一个类作为 配置类,这时候就可以在项目的Main入口类中写入配置信息,那是谁标注这个类 是配置类呢?这就是SpringBootConfiguration起的作用了。
至于AutoConfigurationPackage,就和上文中提及的,用来保存一些全类名包路径,方便spring和我们后续使用。
SpringBoot的启动流程
SpringBoot项目运行的起点就是Main方法的主启动类。点击运行后,会经历4个阶段:服务构建,环境准备,容器创建,填充容器。
服务构建
在SpringApplication的构造方法里,进行服务构建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader; this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
|
- ApplicationContextInitializer:上下文初始化器
- ApplicationListener:监听器 在
spring-boot
和spring-boot-autoconfigure
这两个工程中配置了7个“上下文初始化器”和额 8个“监听器”,这些配置信息会在后续启动过程中使用。
1 2 3 4 5 6 7 8 9 10 11
| --------------- 例:Spring-boot包下的 spring.factories ---------------------
# Initializers org.springframework.context.ApplicationContextInitializer=\\\\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\\\\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners org.springframework.context.ApplicationListener=\\\\ org.springframework.boot.autoconfigure.BackgroundPreinitializer
|
总结:
在SpringApplication的构造方法里,主要就干了一件事 就是 将依赖包以及项目下spring.factories
中的上下文初始化器和监听器加载进Spring容器中,方便在后续启动过程中使用。
环境准备
这个阶段主要在run
方法 中进行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| public ConfigurableApplicationContext run(String... args) {
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); Banner printedBanner = printBanner(environment);
}
|
SpringApplicationRunListeners启动后,就可以利用监听器(保护初始化的8个监听器ApplicationListener)监听Spring走到哪一步了,然后做出自己的逻辑判断。等待所有监听器串行处理完成 之后,继续后续逻辑。
容器创建阶段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public ConfigurableApplicationContext run(String... args) {
context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
return context; }
|
容器:指内部有很多不同的属性,集合以及 配套功能的结构体-ApplicationContext
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
|
填充容器
1 2 3 4 5 6 7 8 9 10 11
| public ConfigurableApplicationContext run(String... args) { refreshContext(context); afterRefresh(context, applicationArguments); listeners.started(context); callRunners(context, applicationArguments); listeners.running(context); }
|
在这一步中会生产滋生提供依旧项目中自定义的所有Bean对象,并且放在容器中。这个过程就是我们常说的自动装配。其涵盖了“Bean生命周期管理”。
SpringBoot启动总结
- 初始化构造器阶段 :主要是:判断项目服务类型;从
spring.factories
中加载监听器和初始化器,方便后续启动使用。
- run方法启动节点:
- 在spring.factories中找到SpringApplicationRunListener(EventPublishingRunListener)构造Spring环境。
- Spring环境构造完成后,创建ApplicationContext上下文容器,并且将初始化构造器中加载的监听器,初始化器,以及run方法开始的SpringApplicationRunListener传递进容器,完成上下文的参数设置。最后,将项目和依赖包下的bean定义加载进BeanDefinitionMap,方便后续实例化。
- 容器完成设置后,开始Bean的生命周期:实例化。最后发布Bean对象创建完成事件,回调我们自定义的额Runner接口,例如ApplicationRunner借口