SpringBoot启动过程有哪些步骤(源码详细分析)
-
构造SpringApplication对象
我们从这里开始源码的解读
通过run方法会生成一个 SpringApplication对象
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
我们进入springApplication方法里面,接着往下看,这个对象在构造的过程中做了哪些事情?
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//表示传入的配置类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//1.推测web应用类型(NONE,PEACTIVE,SERVLET)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//2.从spring.factories中获取BootstrapRegistryInitializer对象
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
//3.从spring.factories中获取ApplicationContextInitializer对象
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//4.从spring.factories中获取ApplicationListener对象 监听事件
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//5.推测出Main类(main()方法所在的类)
this.mainApplicationClass = deduceMainApplicationClass();
}
private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();
getSpringFactoriesInstances(Bootstrapper.class).stream()
.map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
.forEach(initializers::add);
initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
return initializers;
}
推断应用类型:
this.webApplicationType = WebApplicationType.deduceFromClasspath()
通过类路径判断应用类型:
SERVLET
:存在 Servlet API 和DispatcherServlet
(传统 Spring MVC)。
REACTIVE
:存在 Spring WebFlux 的DispatcherHandler
。
NONE
:非 Web 应用。加载引导注册初始化器:
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories()
从
META-INF/spring.factories
加载BootstrapRegistryInitializer
实现类。用于在引导阶段(如配置中心加载)注册自定义组件。
设置初始化器:
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))
通过
SpringFactoriesLoader
加载所有ApplicationContextInitializer
实现类并实例化。这些初始化器会在
ApplicationContext
刷新前执行(如修改环境变量、注册 Bean)。设置监听器:
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class))
加载所有
ApplicationListener
实现类并实例化。这些监听器用于响应应用事件(如上下文启动、失败等)。
推断主应用类:
this.mainApplicationClass = deduceMainApplicationClass()
通过分析调用栈找到包含
main
方法的类(即启动类)。用于日志输出或某些需要主类的场景。
以上是构建SpringApplication所需要完成的一些事情
下面构建完SpringApplication之后开始调用run方法,在这个过程中,又会做哪些事情呢,咱们接着往下看
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//1.创建引导启动器,类似一个SpplicationContext,可以往里面添加一些对象,后续过程中(刷新)
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
//2.从spring.factories中获取SpringApplicationRunListeners对象
//默认会拿到一个EventPoblishingRunListener,它会启动过程的各个阶段发布对应的Application
SpringApplicationRunListeners listeners = getRunListeners(args);
3.发布ApplicationStartingEvent
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//4.将run()的参数封装为DefaultApplicationArguments对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//5.准备Environment
//将包括操作系统,JVM,ServletContext,properties,yaml,Ncos等等配置放入这个对象,是典型的key,value格式
//会发布一个ConfigurableEnvironmentPreParedEvent事件,表示环境已经准备好了,
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//默认spring.beaninfo.ignore=true,表示不需要jkd缓存beanInfo信息,Spring自己会缓存
configureIgnoreBeanInfo(environment);
//打印Banner图片
Banner printedBanner = printBanner(environment);
//6.根据类型创建Spring容器
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//预处理Spring容器:
//7.利用SpringApplicationContextInitaializer初始化Spring容器
//8.发布SpringApplicationContextInitaializerEvent
//9.关闭DefaultBootstrapContext
//10.注册primarySources类,就是run方法存入进来的配置类
//11.发布ApplicationPreparedEvent事件,表示Spring容器已经准备好了
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//12.启动Spring容器,会解析配置类,扫描,启动WebServer,比如tomcat
refreshContext(context);
//空方法,可以重新这个方法,完成自己的一些扩展
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
13.发布ApplicationStartedEvent,表示Spring容器已经启动
listeners.started(context);
//14.从Spring容器中获取ApplicationRunner和ConmmandLinneRunner,并执行其run方法
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
//15.如果出现失败,会发布ApplicationFailedRvent事件,
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
以下具体分析解释:
1. 启动计时与监控
StopWatch stopWatch = new StopWatch();
stopWatch.start();
-
作用:使用
StopWatch
记录应用启动耗时,用于后续日志输出。
2. 初始化引导上下文
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
-
作用:创建
BootstrapContext
,用于在应用启动的早期阶段(如配置中心加载)注册组件。 -
底层机制:通过
BootstrapRegistryInitializer
实现自定义初始化逻辑(如加载外部配置)。
3. 配置 Headless 模式
configureHeadlessProperty();
-
作用:强制设置
java.awt.headless=true
,即使服务器没有图形界面或显示设备,也能正常运行。 -
适用场景:处理图像生成、字体计算等操作(如 PDF 导出)。
4. 获取并触发启动监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
-
getRunListeners
:从META-INF/spring.factories
加载所有SpringApplicationRunListener
实现类(如EventPublishingRunListener
)。 -
listeners.starting()
:触发ApplicationStartingEvent
事件,通知监听器应用开始启动。
5. 准备应用环境
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
-
ApplicationArguments
:封装命令行参数(--key=value
格式),提供便捷的访问接口。 -
prepareEnvironment
:-
创建
ConfigurableEnvironment
(如StandardServletEnvironment
)。 -
加载配置文件(
application.properties
/application.yml
)。 -
触发
ApplicationEnvironmentPreparedEvent
事件,允许监听器修改环境配置(如ConfigFileApplicationListener
加载配置文件)。
-
6. 忽略 BeanInfo 类
configureIgnoreBeanInfo(environment);
-
作用:跳过对
BeanInfo
类的扫描,避免某些 JDK 类的元数据解析问题(如java.beans.Introspector
)。
7. 打印 Banner
Banner printedBanner = printBanner(environment);
-
作用:根据配置输出启动 Banner(默认或自定义),可通过
spring.banner.location
指定 Banner 文件。
8. 创建应用上下文
context = createApplicationContext();
-
根据应用类型(Servlet/Reactive/None)创建对应的
ConfigurableApplicationContext
:-
Servlet:
AnnotationConfigServletWebServerApplicationContext
-
Reactive:
AnnotationConfigReactiveWebServerApplicationContext
-
None:
AnnotationConfigApplicationContext
-
9. 准备上下文
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
-
关键操作:
-
将
Environment
绑定到上下文。 -
执行
ApplicationContextInitializer
初始化器(如设置上下文 ID、注册 Bean)。 -
触发
ApplicationContextInitializedEvent
事件。 -
注册主配置类(
primarySources
)和命令行参数 Bean。 -
加载所有
BeanDefinitionLoader
(如主类、XML 配置等)。
-
10. 刷新上下文(核心步骤)
refreshContext(context);
-
作用:调用
AbstractApplicationContext.refresh()
,完成 Spring 容器的初始化。 -
关键子流程:
-
准备 BeanFactory:注册必要的 Bean(如
environment
、applicationArguments
)。 -
执行
BeanFactoryPostProcessor
:处理配置类的解析(如@Configuration
)。 -
注册
BeanPostProcessor
:干预 Bean 的创建过程(如 AOP 代理)。 -
初始化消息源、事件广播器。
-
创建并初始化所有单例 Bean。
-
启动 Web 服务器(如 Tomcat、Netty)。
-
11. 启动后回调
afterRefresh(context, applicationArguments);
listeners.started(context);
callRunners(context, applicationArguments);
-
afterRefresh
:空方法,留给子类扩展。 -
listeners.started()
:触发ApplicationStartedEvent
,通知监听器应用已启动。 -
callRunners
:执行所有ApplicationRunner
和CommandLineRunner
的run()
方法,用于启动后执行自定义逻辑(如数据初始化)。
12. 完成启动
stopWatch.stop();
new StartupInfoLogger(...).logStarted(...);
listeners.ready(context);
-
记录启动耗时:输出到日志。
-
触发
ApplicationReadyEvent
:通知应用已完全就绪(与ApplicationStartedEvent
的区别在于,此时所有 Bean 已就绪)。
13. 异常处理
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
-
handleRunFailure
:-
触发
ApplicationFailedEvent
事件。 -
关闭应用上下文(如果已创建)。
-
输出错误日志。
-
总结一下 SpringBoot启动过程步骤大致是:
构造SpringApplication对象->调用run方法(准备Environment-打印Banner->创建Spring容器->预处理Spring容器->刷新Spring容器