前言
Spring Boot 的一大核心优势,是其对 嵌入式 Web 容器(Embedded Web Server) 的原生支持。开发者无需将应用打包成 WAR 文件并部署到外部 Tomcat、Jetty 等服务器,只需一个简单的 main 方法,即可启动一个完整的 Web 应用。
本文将深入剖析 Spring Boot 嵌入式 Web 容器的设计原理、支持的容器类型、自动配置机制、性能调优策略,并结合源码与实战案例,帮助开发者全面掌握这一关键技术,提升微服务架构下的部署效率与运维能力。
文章目录
-
- 前言
- [1. 引言:什么是嵌入式 Web 容器?](#1. 引言:什么是嵌入式 Web 容器?)
- [2. 支持的嵌入式容器类型](#2. 支持的嵌入式容器类型)
-
- 如何切换容器?
-
- [示例:切换为 Jetty](#示例:切换为 Jetty)
- [切换为 Undertow](#切换为 Undertow)
- [3. 嵌入式容器的工作原理](#3. 嵌入式容器的工作原理)
-
- [3.1 启动流程概览](#3.1 启动流程概览)
- [3.2 关键接口:`WebServer`](#3.2 关键接口:
WebServer) - [3.3 自动配置机制](#3.3 自动配置机制)
- [4. 核心组件解析](#4. 核心组件解析)
-
- [4.1 `ServletWebServerFactory`](#4.1
ServletWebServerFactory) - [4.2 容器定制化](#4.2 容器定制化)
- [4.1 `ServletWebServerFactory`](#4.1
- [5. 性能调优建议](#5. 性能调优建议)
-
- [5.1 Tomcat 调优参数](#5.1 Tomcat 调优参数)
- [5.2 Undertow 调优建议](#5.2 Undertow 调优建议)
- [5.3 通用优化策略](#5.3 通用优化策略)
- [6. 实战:构建高性能 REST API 服务](#6. 实战:构建高性能 REST API 服务)
-
- 场景:一个高并发用户查询接口
-
- [步骤 1:选择 Undertow 容器](#步骤 1:选择 Undertow 容器)
- [步骤 2:配置优化](#步骤 2:配置优化)
- [步骤 3:启用异步处理](#步骤 3:启用异步处理)
- [7. 与传统部署模式的对比](#7. 与传统部署模式的对比)
- [8. 注意事项与最佳实践](#8. 注意事项与最佳实践)
-
- [✅ 推荐做法](#✅ 推荐做法)
- [❌ 避免陷阱](#❌ 避免陷阱)
- [9. 总结](#9. 总结)
1. 引言:什么是嵌入式 Web 容器?
在传统 Java Web 开发中,典型的部署流程如下:
编写代码 → 打包为 WAR → 部署到 Tomcat/JBoss/WebLogic → 启动服务器
这种方式存在诸多弊端:
- 部署复杂,依赖外部环境
- 版本冲突风险高
- 微服务场景下难以独立部署和扩展
而 Spring Boot 提出了一种全新的模式:嵌入式 Web 容器。
定义 :
嵌入式 Web 容器是指将 Web 服务器(如 Tomcat、Jetty、Undertow)直接打包进应用内部,作为应用的一部分运行,无需外部独立部署。
典型启动方式:
java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
执行后,控制台输出:
Tomcat started on port(s): 8080 (http)
Started Application in 3.2 seconds
一个内嵌的 Tomcat 服务器已随应用一同启动。
2. 支持的嵌入式容器类型
Spring Boot 官方支持三种主流嵌入式 Web 容器:
| 容器 | 说明 |
|---|---|
| Tomcat | 默认容器,由 Apache 提供,功能全面,社区活跃 |
| Jetty | Eclipse 维护,轻量高效,适合高并发、低延迟场景 |
| Undertow | Red Hat 开发,基于 NIO,性能优异,内存占用低 |
如何切换容器?
通过 Maven/Gradle 排除默认容器并引入新容器即可。
示例:切换为 Jetty
xml
<dependencies>
<!-- 排除默认 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>
<!-- 引入 Jetty -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
</dependencies>
切换为 Undertow
xml
<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>
提示:选择依据:
- 通用场景:Tomcat(默认)
- 高并发短连接:Undertow 或 Jetty
- WebSocket 频繁使用:Jetty
3. 嵌入式容器的工作原理
3.1 启动流程概览
SpringApplication.run()被调用- 创建
ApplicationContext - 触发
ApplicationContextInitializer - 调用
onRefresh()方法 - 创建并初始化
WebServer - 启动容器并监听端口
- 发布
ApplicationReadyEvent
3.2 关键接口:WebServer
Spring Boot 抽象了 WebServer 接口,屏蔽不同容器的差异:
java
public interface WebServer {
void start();
void stop();
int getPort();
}
具体实现类包括:
TomcatWebServerJettyWebServerUndertowWebServer
3.3 自动配置机制
Spring Boot 通过条件化配置自动创建 Web 容器。
以 Tomcat 为例:
java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
@Bean
TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
@ConditionalOnClass:确保 Tomcat 类在类路径中@ConditionalOnMissingBean:避免重复创建TomcatServletWebServerFactory:负责创建TomcatWebServer实例
4. 核心组件解析
4.1 ServletWebServerFactory
该工厂接口负责创建具体的 WebServer 实例。
java
public interface ServletWebServerFactory {
WebServer getWebServer(ServletContextInitializer... initializers);
}
ServletContextInitializer 用于注册 Servlet、Filter、Listener。
4.2 容器定制化
可通过配置文件或编程方式定制容器行为。
方式一:配置文件(application.yml)
yaml
server:
port: 8081
servlet:
context-path: /api
tomcat:
max-connections: 8192
max-threads: 200
min-spare-threads: 10
uri-encoding: UTF-8
undertow:
io-threads: 4
worker-threads: 200
buffer-size: 1024
direct-buffers: true
方式二:编程方式(推荐复杂场景)
java
@Component
public class WebServerCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory factory) {
factory.setPort(9090);
factory.setContextPath("/app");
// Tomcat 特定配置
if (factory instanceof TomcatServletWebServerFactory) {
((TomcatServletWebServerFactory) factory)
.addConnectorCustomizers(connector -> {
connector.setProperty("relaxedQueryChars", "|{}[]");
});
}
// Jetty 特定配置
if (factory instanceof JettyServletWebServerFactory) {
((JettyServletWebServerFactory) factory)
.addServerCustomizers(server -> {
server.addBean(new GzipHandler());
});
}
}
}
5. 性能调优建议
5.1 Tomcat 调优参数
| 参数 | 建议值 | 说明 |
|---|---|---|
max-threads |
200--400 | 最大工作线程数 |
min-spare-threads |
50 | 最小空闲线程数 |
accept-count |
100 | 请求等待队列长度 |
max-connections |
8192 | 最大连接数 |
connection-timeout |
20000ms | 连接超时时间 |
5.2 Undertow 调优建议
- 启用直接缓冲区(
direct-buffers: true) - 合理设置 IO 线程数(通常等于 CPU 核心数)
- Worker 线程池大小根据业务类型调整(CPU 密集型可设为核数+1,IO 密集型可更大)
5.3 通用优化策略
- 启用 GZIP 压缩
- 配置合理的 Keep-Alive
- 使用连接池(如 HikariCP)管理数据库连接
- 监控线程池状态(通过 Micrometer + Prometheus)
6. 实战:构建高性能 REST API 服务
场景:一个高并发用户查询接口
步骤 1:选择 Undertow 容器
xml
<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>
步骤 2:配置优化
yaml
server:
port: 8080
undertow:
io-threads: 4
worker-threads: 400
direct-buffers: true
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
步骤 3:启用异步处理
java
@RestController
public class UserController {
@GetMapping("/users/{id}")
public CompletableFuture<ResponseEntity<User>> getUser(@PathVariable Long id) {
return CompletableFuture.supplyAsync(() -> {
User user = userService.findById(id);
return ResponseEntity.ok(user);
});
}
}
异步处理可显著提升吞吐量,避免阻塞主线程。
7. 与传统部署模式的对比
| 对比项 | 传统 WAR 部署 | 嵌入式容器 |
|---|---|---|
| 部署方式 | 外部服务器部署 WAR | JAR 内运行 |
| 启动速度 | 较慢(需启动整个服务器) | 极快(仅启动应用) |
| 独立性 | 依赖外部环境 | 完全自包含 |
| 微服务友好度 | 差 | 极佳 |
| 资源占用 | 高(共享服务器) | 可控(按需分配) |
| 版本管理 | 复杂(容器与应用分离) | 简单(一体化) |
结论:嵌入式容器更适合云原生、微服务、容器化部署场景。
8. 注意事项与最佳实践
✅ 推荐做法
- 生产环境明确指定容器类型,避免依赖默认行为
- 合理配置线程池与连接数,避免资源耗尽
- 使用
WebServerFactoryCustomizer进行复杂定制 - 监控容器指标(QPS、响应时间、线程状态)
- 在 Docker/Kubernetes 中优先使用嵌入式容器
❌ 避免陷阱
- 不要在嵌入式容器中部署多个应用(违背微服务理念)
- 避免过度调优,应基于压测数据
- 注意安全配置(如禁用不必要的 HTTP 方法)
- 日志路径应挂载到外部存储(Docker 场景)
9. 总结
Spring Boot 的嵌入式 Web 容器机制,通过 "应用即服务" 的设计理念,彻底改变了 Java Web 应用的开发与部署方式。
其核心优势包括:
- 简化部署:一键启动,无需外部依赖
- 快速迭代:启动速度快,适合开发调试
- 微服务友好:天然支持独立部署与弹性伸缩
- 灵活定制:支持多种容器,可深度配置
- 云原生适配:完美契合 Docker、Kubernetes 等现代基础设施
掌握嵌入式容器的原理与调优方法,是构建高性能、高可用 Spring Boot 应用的关键一步。
版权声明:本文为作者原创,转载请注明出处。