Spring Boot 启动类与完整启动过程终极拆解(2025 最新最全版)
这篇直接干掉 99% 的面试题 + 让你看懂所有启动日志 + 能手写启动流程图!
基于 Spring Boot 3.3 + Spring Framework 6.1(当前最新稳定版)
一、启动类到底长什么样?(2025 标准写法)
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
这 8 行代码背后干了 2000+ 行的事!我们把它拆成 12 个阶段。
二、完整启动流程 12 大阶段(建议保存这张图)
1. 准备阶段(main方法开始)
↓
2. 创建 SpringApplication 实例
↓
3. 推断应用类型(Servlet / Reactive)
↓
4. 加载 Initializers(初始化器)
↓
5. 加载 Listeners(监听器)
↓
6. 推断并设置主类(main方法所在的类)
↓
7. run() 方法真正执行
↓
8. 开始计时 + 打印 Banner
↓
9. 创建 ApplicationContext(Servlet环境就是 AnnotationConfigServletWebServerApplicationContext)
↓
10. prepareContext():加载启动类、执行 Initializers、发布 contextPrepared/contextLoaded 事件
↓
11. refreshContext() → 真正启动 Spring 容器(最重头的 12 个步骤)
↓
12. afterRefresh() + 启动完成 + 打印启动耗时 + 发布 started 事件 + 调用 CommandLineRunner / ApplicationRunner
三、@SpringBootApplication 到底是啥?(复合注解拆解)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // ← 就是一个 @Configuration
@EnableAutoConfiguration // ← 最最最核心!开启自动配置
@ComponentScan // ← 扫描当前包及子包的 @Component
public @interface SpringBootApplication {
// 可以加 exclude 排除自动配置
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
// 可以指定扫描包
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
}
四、SpringApplication.run() 内部到底干了什么?(核心源码精简版)
public ConfigurableApplicationContext run(String... args) {
// 1. 启动计时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2. 创建上下文和异常报告对象
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
// 3. 配置 Headless(服务器无图形界面)
configureHeadlessProperty();
// 4. 创建并启动监听器(加载 spring.factories 中的 ApplicationListener)
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 5. 准备环境(读取 application.yml + 命令行参数)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 6. 打印 Banner(可以自定义)
Banner printedBanner = printBanner(environment);
// 7. 创建 ApplicationContext(Servlet 环境就是 AnnotationConfigServletWebServerApplicationContext)
context = createApplicationContext();
// 8. 加载失败分析器(启动失败给出友好提示)
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class);
// 9. 准备上下文(最关键!加载启动类、执行 Initializers)
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 10. 刷新容器(Spring 核心!执行所有 BeanFactoryPostProcessor、BeanPostProcessor)
refreshContext(context);
// 11. 刷新后扩展点
afterRefresh(context, applicationArguments);
// 12. 停止计时 + 发布 started 事件 + 执行 Runner
stopWatch.stop();
listeners.started(context);
callRunners(context, applicationArguments);
// 13. 发布 running 事件 → 启动完成!
listeners.running(context);
return context;
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
}
五、最重要的 5 个 spring.factories 文件(记住路径!)
| 文件路径(在各个 starter jar 中) | 作用 |
|---|---|
| META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports | 自动配置类列表(Spring Boot 3 新格式) |
| META-INF/spring.factories(兼容旧格式) | 旧版自动配置、Initializer、Listener |
| META-INF/spring/org.springframework.boot.ApplicationContextInitializer | 上下文初始化器 |
| META-INF/spring/org.springframework.boot.ApplicationRunner | Runner(启动后执行) |
| META-INF/spring/org.springframework.boot.CommandLineRunner | 同上 |
六、启动日志到底哪行是关键?(真实日志对应)
2025-04-05 10:00:00.123 INFO 12345 --- [ main] com.example.DemoApplication : Starting DemoApplication using Java 21
2025-04-05 10:00:00.456 INFO 12345 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2025-04-05 10:00:01.789 INFO 12345 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Welcome page enabled
2025-04-05 10:00:02.234 INFO 12345 --- [ main] o.s.b.d.a.o.OptionalLiveReloadServer : LiveReload server is running
2025-04-05 10:00:02.567 INFO 12345 --- [ main] com.example.DemoApplication : Started DemoApplication in 3.456 seconds (process running for 4.123)
对应阶段:
- Starting → 开始创建 SpringApplication
- Tomcat initialized → 创建内嵌 Web 服务器(WebServerApplicationContext)
- Started → refreshContext 完成,Runner 执行完毕
七、2025 年推荐的 6 种自定义启动方式
// 1. 最常用
SpringApplication.run(DemoApplication.class, args);
// 2. 排除自动配置
new SpringApplicationBuilder(DemoApplication.class)
.profiles("prod")
.exclude(DataSourceAutoConfiguration.class)
.run(args);
// 3. 自定义 Banner(resources/banner.txt)
new SpringApplication(DemoApplication.class)
.setBannerMode(Banner.Mode.OFF)
.run(args);
// 4. Fluent API 方式(推荐!)
new SpringApplicationBuilder()
.sources(DemoApplication.class)
.bannerMode(Banner.Mode.CONSOLE)
.profiles("dev")
.run(args);
// 5. 完全编程式(微服务网关常用)
SpringApplication app = new SpringApplication(DemoApplication.class);
app.setWebApplicationType(WebApplicationType.REACTIVE); // 改成响应式
app.run(args);
// 6. 自定义监听器
app.addListeners(new MyApplicationListener());
八、启动完成后想干点啥?用这俩
// 方式1:实现 ApplicationRunner(推荐,带参数)
@Component
@Order(1) // 执行顺序
public class MyRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("应用启动完成,执行初始化任务");
}
}
// 方式2:实现 CommandLineRunner
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) {
// 适合接收 main 方法参数
}
}
九、面试高频问题秒杀答案
| 问题 | 标准答案 |
|---|---|
| Spring Boot 是怎么启动 Tomcat 的? | 通过 WebServerFactoryAutoConfiguration 自动配置 → 创建 TomcatWebServer |
| 为什么不写 web.xml 也能启动? | 内嵌 Tomcat + DispatcherServletAutoConfiguration 自动注册 Servlet |
| 启动类为什么要放在最外层包? | @ComponentScan 默认扫描启动类所在包及其子包 |
| 怎么关闭某个自动配置? | 3 种方式:exclude、spring.xxx.enabled=false、自己定义 Bean 覆盖 |
| 启动日志里 “Started xxx in x seconds” 之前干了啥? | 创建容器 → 加载 BeanDefinition → refresh() → 初始化所有单例 Bean |
现在你已经彻底掌握了 Spring Boot 从 main 方法到真正启动的完整链路!
这套流程图 + 12 个阶段背熟,阿里、字节、腾讯的面试官都拿你没办法!
下一步你要哪个硬核主题?
- 手把手带你写一个自定义 starter(完整发布到私服)
- Spring Boot 3 + AOT + GraalVM Native 编译全流程
- Spring Boot Actuator 生产监控全家桶
- Spring Boot 3 热部署原理解析
直接告诉我,我继续给你拆到原子级!