这个异常的本质是:Spring Boot 判断应用是 Web 应用,决定启动
ServletWebServerApplicationContext,但容器里没有一个能生成 Web 服务器的ServletWebServerFactorybean。要么少了spring-boot-starter-web,要么主类缺了@SpringBootApplication,要么它本就不该当 Web 应用跑。
Issue & Env(案发现场与环境)
- 现象:应用启动到一半直接失败,控制台报 ApplicationContextException,进程退出。
- 环境:Spring Boot 2.x / 3.x。常见于写批处理、CLI 工具却引进了 Web 依赖,或单元测试没开启自动配置。
StackTrace(堆栈日志)
标准启动失败堆栈:
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:163)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:596)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:305)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1307)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1296)
at com.example.demo.MainEntryPoint.main(MainEntryPoint.java:12)
Caused by: org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory(ServletWebServerApplicationContext.java:209)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:179)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:158)
... 9 more
Reproduce(复现代码)
主类漏写 @SpringBootApplication,SpringApplication.run 找不到自动配置入口:
public class MainEntryPoint {
public static void main(String[] args) {
SpringApplication.run(MainEntryPoint.class, args);
}
}
运行后就会在启动阶段抛上面那段异常。
Root Cause(根因分析)
SpringApplication 启动时,会先根据 classpath 推断应用类型:有 servlet 相关类就当作 SERVLET,有响应式就当作 REACTIVE,都没有就是 NONE。一旦推断成 SERVLET,它会创建 ServletWebServerApplicationContext。这个上下文要启动内嵌容器,必须先从容器里拿到一个 ServletWebServerFactory bean。
正常 Web 应用里,@SpringBootApplication 的自动配置会根据 spring-boot-starter-web 注册一个 TomcatServletWebServerFactory。三条路都会让这个 bean 缺失:
- 主类缺
@SpringBootApplication,自动配置根本没启动。 - classpath 有 servlet API 或
spring-webmvc,却没带spring-boot-starter-web。典型是批处理、CLI 项目被动引进了 Web 相关依赖,被误判成 Web 应用。 - 测试里用了
@SpringBootTest或@ContextConfiguration,但只加载了局部配置类,没触发自动配置。
The Fix(解决方案)
Web 应用就该有 Web 依赖和主类注解。检查两件事:主类补上 @SpringBootApplication;pom.xml 里确认有 spring-boot-starter-web。
非 Web 应用(批处理、定时任务、CLI),明确告诉 Spring Boot 别启动 Web 服务器:
spring.main.web-application-type=none
或 YAML 写法:
spring:
main:
web-application-type: none
测试场景,给配置类或测试类补上 @EnableAutoConfiguration,或手动提供一个 ServletWebServerFactory bean。最省事的是让 @SpringBootTest 走完整自动配置,而不是只拼少数几个配置类。
