每日Java面试场景题知识点之-SpringBoot启动流程

每日Java面试场景题知识点之-SpringBoot启动流程

一、面试场景引入

面试官:"你平时都用SpringBoot开发,那你说说SpringBoot的启动流程是怎样的?"

这道题是Java后端面试中的高频题,考察的不仅是对框架的使用熟练度,更是对底层原理的理解深度。本文将从源码级别带你完整走一遍SpringBoot的启动流程。

二、一切始于run方法

当我们启动一个SpringBoot应用时,入口永远是这样的:

java 复制代码
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

这行看似简单的 SpringApplication.run(),实际上包含了SpringBoot启动的完整生命周期。我们可以将整个启动流程分为两大阶段:构造阶段运行阶段

三、构造阶段:SpringApplication的初始化

当我们调用 new SpringApplication(primarySources) 时,框架主要完成了以下几件关键事情:

3.1 推断Web应用类型

通过检查类路径下是否存在特定的类,来决定应用的类型:

  • 如果存在 javax.servlet.Servletorg.springframework.web.context.ConfigurableWebApplicationContext,则推断为 SERVLET 类型
  • 如果存在 org.springframework.web.reactive.DispatcherHandler,则推断为 REACTIVE 类型
  • 否则推断为 NONE(非Web应用)

源码对应:

java 复制代码
this.webApplicationType = WebApplicationType.deduceFromClasspath();

3.2 加载ApplicationContextInitializer

通过SPI机制从 META-INF/spring.factories 中加载所有配置好的初始化器。这些初始化器会在容器刷新之前被回调执行,用于对ApplicationContext进行定制化设置。

java 复制代码
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

3.3 加载ApplicationListener

同样通过SPI机制加载所有监听器,用于在启动过程中监听各种事件,如应用启动失败、上下文刷新完成等。

java 复制代码
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

3.4 推断主应用类

通过异常栈帧信息推断出包含main方法的主应用类:

java 复制代码
this.mainApplicationClass = deduceMainApplicationClass();

四、运行阶段:run方法核心流程

run() 方法是SpringBoot启动的真正核心逻辑,下面逐步拆解:

4.1 创建并启动计时器

java 复制代码
StopWatch stopWatch = new StopWatch();
stopWatch.start();

用于记录应用启动耗时,启动完成后会输出日志。

4.2 创建引导上下文

java 复制代码
DefaultBootstrapContext bootstrapContext = createBootstrapContext();

创建引导上下文,用于在启动阶段提供环境共享和临时Bean的管理。

4.3 配置Headless属性

java 复制代码
configureHeadlessProperty();

设置 java.awt.headless=true,确保在无显示设备的服务器环境下,图形相关操作不会抛出异常。

4.4 获取RunListeners并发送starting事件

java 复制代码
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);

加载所有的 SpringApplicationRunListener,并触发 starting 事件,标志着应用启动流程正式开始。

4.5 封装命令行参数

java 复制代码
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

将main方法传入的命令行参数封装为 ApplicationArguments 对象,方便后续统一处理。

4.6 准备环境(关键步骤)

java 复制代码
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

这是启动流程中极为重要的一步:

  • 创建 ConfigurableEnvironment 对象
  • 加载配置文件(application.yml/properties)
  • 解析命令行参数、系统属性、操作系统环境变量等多层配置源
  • 按照严格的优先级顺序进行配置覆盖
  • 触发 environmentPrepared 事件

4.7 打印Banner

java 复制代码
Banner printedBanner = printBanner(environment);

在控制台打印SpringBoot标志性的Banner图案,也可以自定义Banner。

4.8 创建ApplicationContext

java 复制代码
context = createApplicationContext();

根据之前推断的Web应用类型,创建不同的ApplicationContext实现类:

  • SERVLET类型 → AnnotationConfigServletWebServerApplicationContext
  • REACTIVE类型 → AnnotationConfigReactiveWebServerApplicationContext
  • NONE类型 → AnnotationConfigApplicationContext

4.9 准备上下文

java 复制代码
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

这一步完成了多项关键工作:

  • 将Environment绑定到ApplicationContext
  • 执行所有ApplicationContextInitializer的initialize方法
  • 触发 contextPrepared 事件
  • 注册主配置类作为BeanDefinition
  • 触发 contextLoaded 事件

4.10 刷新上下文(最核心步骤)

java 复制代码
refreshContext(context);

这是整个启动流程中最复杂、最核心的一步,底层调用的是Spring的 AbstractApplicationContext.refresh() 方法。该方法包含以下关键子步骤:

  1. prepareRefresh:刷新前准备,记录启动时间,设置活跃标志
  2. obtainFreshBeanFactory:创建/刷新BeanFactory,加载BeanDefinition
  3. prepareBeanFactory:对BeanFactory进行功能填充(类加载器、后置处理器等)
  4. postProcessBeanFactory:子类可重写的后置处理钩子
  5. invokeBeanFactoryPostProcessors :执行BeanFactoryPostProcessor,这是自动配置的核心入口,@EnableAutoConfiguration在此生效
  6. registerBeanPostProcessors:注册BeanPostProcessor
  7. initMessageSource:初始化国际化资源
  8. initApplicationEventMulticaster:初始化事件广播器
  9. onRefresh:子类特殊初始化,如内嵌Tomcat在此启动
  10. registerListeners:注册监听器
  11. finishBeanFactoryInitialization:实例化所有非懒加载的单例Bean
  12. finishRefresh:完成刷新,发布ContextRefreshedEvent

其中第9步 onRefresh,在Servlet Web应用中,会调用 createWebServer() 方法,完成内嵌Tomcat/Jetty/Undertow的启动。

4.11 执行afterRefresh

java 复制代码
afterRefresh(context, applicationArguments);

刷新后的钩子方法,默认为空实现,供子类扩展使用。

4.12 停止计时器并发送started事件

java 复制代码
stopWatch.stop();
listeners.started(context, timeTakenToStartup);

记录启动耗时,触发 started 事件,表示ApplicationContext已经刷新完成,Bean已就绪。

4.13 执行Runner

java 复制代码
callRunners(context, applicationArguments);

调用所有实现了 ApplicationRunnerCommandLineRunner 的Bean,这是业务侧常用的启动后执行逻辑的扩展点。

4.14 发布ready事件

java 复制代码
listeners.ready(context, timeTakenToStartup);

触发 ready 事件,标志着SpringBoot应用正式启动完成,可以对外提供服务。

五、启动流程核心事件时间线

整个启动流程中,关键事件按时间顺序依次触发:

  1. starting → 应用启动开始
  2. environmentPrepared → 环境准备完成
  3. contextPrepared → 上下文创建完成
  4. contextLoaded → BeanDefinition加载完成
  5. started → 上下文刷新完成,Bean已就绪
  6. ready → 应用完全启动,可接收请求

六、面试加分点

6.1 SpringBoot和Spring的启动区别

Spring的传统启动需要手动配置web.xml、DispatcherServlet、ContextLoaderListener等,而SpringBoot通过自动配置和内嵌Web容器,将这一切自动化,开发者只需一个main方法即可启动。

6.2 关键扩展点总结

  • ApplicationContextInitializer:上下文刷新前的定制化
  • ApplicationListener:监听启动过程中的各类事件
  • SpringApplicationRunListener:监听run方法的各阶段
  • BeanFactoryPostProcessor:Bean定义加载后、实例化前的修改
  • BeanPostProcessor:Bean实例化后的前后置处理
  • ApplicationRunner/CommandLineRunner:启动完成后的业务逻辑

6.3 内嵌Tomcat是如何启动的

refreshContextonRefresh 阶段,ServletWebServerApplicationContext 会调用 createWebServer(),该方法会从BeanFactory中获取 ServletWebServerFactory(默认TomcatServletWebServerFactory),创建并启动Web服务器。

七、总结

SpringBoot的启动流程可以用一句话概括:构造SpringApplication推断应用类型和加载扩展点,然后通过run方法完成环境准备、上下文创建、自动配置、Bean实例化和内嵌容器启动,最终发布ready事件表示应用就绪。

掌握这些核心流程,不仅能帮你应对面试,更能在实际开发中快速定位启动阶段的各类问题,是Java后端工程师的必备技能。

感谢读者观看

相关推荐
RyFit1 小时前
Java + AI 实战:Spring AI 从入门到企业级落地
java·人工智能·spring
Raink老师1 小时前
【AI面试临阵磨枪-69】如何设计一个支持百万级工具的 Agent 系统?如何快速路由与选择工具?
人工智能·面试·职场和发展
Raink老师2 小时前
【AI面试临阵磨枪-77】音视频 + AI:实时字幕、翻译、降噪、虚拟人、多模态对话
人工智能·面试·音视频
ZhengEnCi2 小时前
01-如何监听接口调用情况?
java·spring boot·后端
JAVA面经实录9173 小时前
MyBatis学习体系
java·mybatis
java1234_小锋3 小时前
在 Spring AI 中如何实现函数调用(Function Calling)?请说明其基本原理和应用场景。
java·人工智能·spring
小马爱打代码4 小时前
Spring源码 第九篇:Spring 5 源码深度拆解 - Spring 事件驱动模型
java·后端·spring
ForgeAI码匠5 小时前
ForgeAdmin|Spring Boot 3 后台框架的自动配置设计:少写配置,多做组合
java·spring boot·后端
tongluowan0075 小时前
Redisson的参数及工作原理
java·redis·lua·分布式锁