在现代化Java应用开发中,Spring Boot的内嵌Web容器特性彻底改变了传统Java Web应用的部署方式。不同于需要将应用打包成WAR文件部署到外部Servlet容器的传统模式,Spring Boot通过将Web服务器直接集成到应用中,实现了"开箱即用"的轻量级部署体验。这一设计哲学不仅简化了开发流程,更契合了云原生时代对应用可移植性和独立性的要求。

Spring Boot 3.x版本默认支持三种主流的Servlet容器实现,每种容器都有其独特的性能特性和适用场景:
在选择具体的内嵌容器时,开发者需要综合评估以下技术指标:
性能维度
功能特性
生态系统
截至2025年,各容器的最新稳定版本与Spring Boot 3.x的兼容情况如下:
值得注意的是,从Spring Boot 3.0开始,所有容器都已完成从javax到jakarta命名空间的迁移,开发者需要确保依赖库也完成了相应升级。
对于特定类型的应用,容器选择策略有所不同:
微服务架构
边缘计算场景
传统企业应用
在实际开发中,Spring Boot通过自动配置机制简化了容器切换过程,开发者只需在pom.xml或build.gradle中排除默认的tomcat-starter并引入目标容器依赖即可完成切换。这种设计既保持了灵活性,又不会增加配置复杂度。
在Spring Boot的自动配置魔法背后,ServletWebServerFactoryAutoConfiguration扮演着内嵌Web容器装配的总调度角色。这个自动配置类通过精密的条件判断机制,实现了对Tomcat、Jetty、Undertow等容器的智能选择与初始化。
该配置类的生效首先依赖于@ConditionalOnClass注解对Servlet和ServletWebServerFactory类的检测:
@ConditionalOnClass({ Servlet.class, ServletWebServerFactory.class })
@ConditionalOnWebApplication(type = Type.SERVLET)这两个条件确保只有当项目是Servlet类型的Web应用,且类路径下存在Servlet相关类时才会激活配置。这种设计使得非Web应用或响应式Web应用(如WebFlux)不会加载不必要的配置。
Spring Boot通过@ConditionalOnMissingBean注解实现了"容器自动选择"的默认逻辑:
@ConditionalOnMissingBean(
value = ServletWebServerFactory.class,
search = SearchStrategy.CURRENT
)这个条件会在当前应用上下文中没有手动注册ServletWebServerFactory bean时生效,此时Spring Boot会按照预设的优先级自动配置容器。值得注意的是,在2025年的Spring Boot 3.2版本中,这个搜索策略进一步优化了父子容器的查找效率。
对于每种支持的容器,都有对应的内部配置类:
Tomcat配置:
@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
public static class TomcatWebServerFactoryCustomizerConfiguration {
@Bean
public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(...) {
return new TomcatWebServerFactoryCustomizer(...);
}
}只有当检测到Tomcat相关类存在时,才会创建Tomcat定制器。这种设计使得项目在没有Tomcat依赖时完全不会加载相关配置。
Jetty配置:
@ConditionalOnClass({ Server.class, Loader.class, WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class JettyServletWebServerFactoryConfiguration {
@Bean
public JettyServletWebServerFactory JettyServletWebServerFactory(...) {
return new JettyServletWebServerFactory(...);
}
}Jetty的配置要求更严格,必须检测到org.eclipse.jetty.server.Server等核心类才会激活。
Spring Boot通过@AutoConfigureOrder控制不同容器配置的加载顺序:
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class ServletWebServerFactoryAutoConfiguration {
// 配置内容
}这种机制确保Web服务器配置会优先于其他自动配置执行,在2025年的版本中,这个优先级系统增加了对并行初始化的支持。
开发者可以通过多种方式覆盖默认配置:
例如,要强制使用Undertow,只需排除Tomcat依赖并添加Undertow starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>在调试时,可以通过启动参数查看条件评估详情:
--debug这将输出类似如下的条件匹配报告:
ServletWebServerFactoryAutoConfiguration matched:
- @ConditionalOnClass found required classes 'javax.servlet.Servlet',
'org.springframework.web.servlet.DispatcherServlet' (OnClassCondition)
- found 'session' scope (OnWebApplicationCondition)
TomcatServletWebServerFactory matched:
- @ConditionalOnClass found required class 'org.apache.catalina.startup.Tomcat'
(OnClassCondition)在最新版本中,条件判断系统引入了两级缓存机制:
在Spring Boot的自动化配置体系中,Web容器工厂的创建过程展现了框架"约定优于配置"的核心思想。当应用启动时,ServletWebServerFactoryAutoConfiguration会根据classpath中的依赖自动激活对应的容器工厂创建逻辑,这一过程涉及多重条件判断和定制化配置机制。

ServletWebServerFactoryAutoConfiguration通过@ConditionalOnClass注解实现精确的条件控制。以Tomcat为例,当检测到Tomcat相关类存在时(即spring-boot-starter-web默认场景),配置类中的tomcatServletWebServerFactoryCustomizer方法会被激活。这个过程中关键的条件判断包括:
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)同样的逻辑适用于Jetty容器,当检测到Jetty相关类且未手动注册其他工厂时,JettyServletWebServerFactory会被创建。这种条件装配机制确保了不同容器实现之间的互斥性。
TomcatServletWebServerFactory的创建过程包含三个关键阶段:
factory.addConnectorCustomizers(connector -> {
connector.setProperty("relaxedQueryChars","[]|{}^");
});JettyServletWebServerFactory的初始化流程则展现出不同的技术特点:
两种工厂都提供了丰富的定制扩展能力:
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
return factory -> factory.addContextCustomizers(context -> {
context.setSessionTimeout(30, TimeUnit.MINUTES);
});
}不同工厂的配置对性能有直接影响:
在容器选择方面,基准测试显示:Tomcat在传统同步阻塞场景下表现稳定,而Jetty在高并发长连接场景(如WebSocket)中更具优势。Undertow则在内存占用方面表现突出,适合资源受限环境。
在Spring Boot应用启动过程中,ServletWebServerApplicationContext扮演着承上启下的关键角色。这个特殊的应用上下文不仅继承了传统的AnnotationConfigServletWebServerApplicationContext功能,更通过精妙的设计实现了内嵌Web容器的自动化管理。
当SpringApplication.run()方法执行到refreshContext()阶段时,ServletWebServerApplicationContext会经历完整的初始化流程。其中最关键的是onRefresh()方法的实现,这里触发了WebServer的创建逻辑。在2025年的Spring Boot 3.2版本中,这个过程的线程安全性得到了显著提升,通过双重检查锁机制确保容器只初始化一次。
具体执行流程如下:
ServletWebServerApplicationContext通过类型为ServletWebServerFactory的Bean来创建WebServer。这个工厂实例实际上是在ServletWebServerFactoryAutoConfiguration阶段就已经准备好的。在2025年最新的Spring Boot实现中,获取过程增加了缓存优化:
private ServletWebServerFactory getWebServerFactory() {
String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing " +
"ServletWebServerFactory bean.");
}
if (beanNames.length > 1) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple " +
"ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
}
return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}这段代码展示了Spring Boot严格的约定优于配置原则:当存在多个工厂Bean时会直接抛出异常,这与早期版本允许通过配置选择的行为形成鲜明对比。
获取工厂实例后,真正的容器创建过程在WebServer的initialize()方法中完成。以Tomcat为例,这个阶段会执行以下关键操作:
在2025年的实现中,新增了对GraalVM原生镜像的特别支持,当检测到运行在Native Image环境时,会自动优化类加载策略。
WebServer启动过程中,Spring Boot通过事件机制实现了高度的可扩展性:
开发者可以通过监听这些事件实现自定义初始化逻辑。最新版本中,事件发布改为基于Project Reactor的响应式流,提高了高并发场景下的处理效率。
在容器启动后,ServletWebServerApplicationContext还负责管理WebServer的生命周期:
特别值得注意的是,2025年版本引入了自适应线程池配置,能够根据系统CPU核心数和内存大小自动优化线程池参数,这在容器化部署环境中表现尤为突出。
当容器启动失败时,Spring Boot提供了详细的诊断信息:
开发人员可以通过设置debug=true获取更详细的启动过程日志,这在排查复杂的依赖冲突问题时非常有用。最新版本还增加了交互式诊断shell,当应用启动失败时可以直接连接进行状态检查。
在Spring Boot应用中切换或定制内嵌Web容器是开发者经常需要面对的场景。2025年的最新Spring Boot 3.2版本依然保持着对Tomcat、Jetty和Undertow三大主流容器的完整支持,但具体的切换方式和定制手段相比早期版本有了更优雅的实现。

1. 排除依赖+引入新依赖(推荐方式) 这是目前最主流的切换方式,以切换到Jetty为例:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>2. 通过配置属性强制指定 在application.properties中设置:
spring.main.web-application-type=servlet
spring.main.web-environment=true
server.servlet.web-application-type=servlet这种方式需要配合对应的starter依赖才能生效。
3. 编程式切换(高级用法) 通过实现WebServerFactoryCustomizer接口:
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory>
tomcatCustomizer() {
return factory -> {
factory.addConnectorCustomizers(connector -> {
connector.setPort(8081);
});
};
}2025年的基准测试显示三大容器在Spring Boot 3.2下的表现:
生产环境选型建议:
线程池优化配置 对于Tomcat的线程池定制:
server:
tomcat:
threads:
max: 200
min-spare: 20
accept-count: 100
connection-timeout: 5000msUndertow的Worker配置
@Bean
public UndertowServletWebServerFactory
undertowServletWebServerFactory() {
UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.addBuilderCustomizers(builder -> {
builder.setWorkerOptions(
new WorkerOptions()
.setWorkerThreads(200)
.setIoThreads(Runtime.getRuntime().availableProcessors() * 2)
);
});
return factory;
}SSL/TLS高级配置 针对不同容器的SSL配置差异:
# Tomcat专用配置
server.ssl.tomcat.negotiable-protocols=TLSv1.3,TLSv1.2
server.ssl.tomcat.truststore-password=changeit
# Jetty专用配置
server.ssl.jetty.need-client-auth=true
server.ssl.jetty.want-client-auth=false
# Undertow专用配置
server.ssl.undertow.enable-http2=true
server.ssl.undertow.enable-ocsp=true通过实现特定接口可以深度监控容器状态:
@Component
public class TomcatHealthContributor implements
HealthIndicator, ServletContextAware {
private ServletContext servletContext;
@Override
public Health health() {
Tomcat tomcat = (Tomcat) servletContext.getAttribute(
"org.apache.catalina.core.StandardService");
// 自定义健康检查逻辑
return Health.up().build();
}
@Override
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
}端口冲突问题 当出现"Port already in use"错误时,可以:
netstat -ano查找占用端口的进程server.port=0让系统自动分配可用端口@SpringBootTest(webEnvironment = RANDOM_PORT)类加载冲突
切换容器时常见的NoClassDefFoundError通常是由于:
mvn dependency:tree检查依赖关系启动超时问题 对于大型应用可能需要调整启动超时时间:
server.tomcat.connection-timeout=60000
server.jetty.idle-timeout=60000
server.undertow.no-request-timeout=60000建议为容器切换编写专门的集成测试:
@SpringBootTest
class ContainerSwitchTest {
@Autowired
private ServletWebServerApplicationContext context;
@Test
void testRunningContainerType() {
assertThat(context.getWebServer())
.isInstanceOf(JettyWebServer.class);
}
}在技术面试中,Spring Boot内嵌Web容器的启动机制是高频考察点,以下从源码层面解析几个典型问题的技术要点:
当面试官询问"Spring Boot如何启动内嵌Tomcat"时,需要把握三个关键环节:
针对"如何切换内嵌容器"的问题,需要区分不同场景的解决方案:
依赖排除法(推荐)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>这种方式的优势在于完全遵循Spring Boot的自动配置机制,通过修改pom.xml即可完成切换,无需额外编码。
编程式配置
@Bean
public ServletWebServerFactory servletWebServerFactory() {
return new JettyServletWebServerFactory();
}适用于需要动态选择容器的场景,但会覆盖自动配置逻辑,需要开发者自行处理SSL、线程池等配置。
属性开关法
spring.main.web-application-type=servlet
server.servlet=jetty在Spring Boot 2.4+版本中新增的配置方式,但实际效果取决于具体版本实现。
当被问及容器定制时,可以围绕以下维度展开:
基础参数配置 通过application.yml的server前缀配置:
server:
port: 8443
tomcat:
max-threads: 200
connection-timeout: 5s高级定制接口
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() {
return factory -> factory.addConnectorCustomizers(connector -> {
connector.setProperty("relaxedQueryChars", "[]");
});
}@Bean
public ServletContextInitializer servletContextInitializer() {
return servletContext -> {
servletContext.setSessionTimeout(30);
};
}性能调优要点
Q:为什么自定义的ServletWebServerFactory不生效? A:检查是否同时存在多个实现类,Spring Boot会优先采用用户自定义Bean。同时注意@Order注解的优先级设置。
Q:如何实现容器热重启? A:通过实现SmartLifecycle接口,控制WebServer的start/stop方法。但需要注意Session保持问题,生产环境建议使用Spring Cloud Gateway实现动态路由。
Q:内嵌容器与独立部署的性能差异? A:在Spring Boot 3.x中,内嵌模式通过优化类加载机制(使用ModifiedClassPathRunner)已大幅缩小差距。基准测试显示,在并发量<10K的场景下差异不超过5%。
通过结合ServletWebServerFactoryAutoConfiguration的源码(特别是ConditionalOnMissingBean的判断逻辑)和实际配置案例,可以系统性地回答这类面试问题。对于高级岗位,还需要准备Reactive WebServer(Netty)的对比分析,以及如何通过Instrumentation实现容器指标的监控暴露。
[1] : https://blog.csdn.net/zp357252539/article/details/147181807
[2] : https://www.cnblogs.com/steakliu/p/17506055.html
[3] : https://cloud.tencent.com/developer/article/2324111
[4] : https://blog.csdn.net/iceveil/article/details/150265579