乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 Spring Boot 概述

    • 章节导读:Spring Boot概述与核心理念
    • Spring Boot是什么
    • Spring Boot与Spring Framework的关系
    • 约定优于配置
  • 第2章 快速入门与第一个应用

    • 章节导读:快速入门与第一个应用
    • SpringApplication
    • 第一个Spring Boot应用
  • 第3章 起步依赖与版本管理

    • 章节导读:起步依赖与版本管理
    • 起步依赖
    • BOM版本管理
  • 第4章 自动配置原理

    • 章节导读:自动配置原理
    • 自动配置原理
    • AutoConfigurationImportSelector
    • 自动配置报告
  • 第5章 核心注解

    • 章节导读:核心注解
    • @SpringBootApplication
    • @EnableAutoConfiguration
    • @ConditionalOnClass
    • @ConditionalOnMissingBean
    • @ConditionalOnBean
    • @ConditionalOnProperty
  • 第6章 外部化配置与属性绑定

    • 章节导读:外部化配置与属性绑定
    • 外部化配置
    • @ConfigurationProperties
    • @Value
    • 配置属性优先级
  • 第7章 Profile 与环境切换

    • 章节导读:Profile与环境切换
    • @Profile
    • 多环境配置文件
  • 第8章 内嵌服务器与部署

    • 章节导读:内嵌服务器与部署
    • 内嵌服务器
    • Fat Jar
  • 第9章 Actuator 与监控

    • 章节导读:Actuator与监控
    • Actuator Health
    • Actuator Info
    • Actuator Metrics
    • 自定义Endpoint
    • 自定义HealthIndicator
  • 第10章 开发工具与最佳实践

    • 章节导读:开发工具与最佳实践
    • Banner自定义
    • 热部署

内嵌服务器

一句话定位:Spring Boot 将 Tomcat、Jetty、Undertow 等 Servlet 容器直接嵌入应用内部,通过 java -jar 即可启动完整 Web 服务,彻底省去外部 WAR 部署和容器管理的繁琐步骤。


定义与作用

在传统的 SSM(Spring + Spring MVC + MyBatis)开发模式中,应用必须打包为 WAR 文件,然后部署到外部 Tomcat 的 webapps 目录中,再启动 Tomcat 服务。这一过程涉及:修改 server.xml、处理上下文路径、解决类加载冲突、管理容器版本等重复劳动。

Spring Boot 的**内嵌服务器(Embedded Server)**机制将 Servlet 容器作为普通依赖引入,使其随 Spring 应用上下文一同创建和销毁。应用从"部署到容器"变为"容器即应用"。

对比维度传统 SSM 外置容器Spring Boot 内嵌容器
打包格式WAR 文件可执行 JAR(Fat JAR)
部署操作复制 WAR 到 Tomcat/webappsjava -jar app.jar
端口配置修改 server.xmlapplication.yml 中 server.port
容器版本管理运维团队统一维护Maven 依赖控制,应用自带
启动速度容器先启动,再加载应用应用与容器同时初始化,更快
微服务适配一个 Tomcat 多应用,耦合高一个应用一个进程,天然隔离

适用范围:Spring Boot 2.7.x 默认内嵌 Tomcat 9.x(支持 Servlet 4.0)。可通过替换 Starter 切换为 Jetty 或 Undertow,无需修改业务代码。


适用位置与常用属性

内嵌服务器由 spring-boot-starter-web 自动引入,开发者无需手动编写代码触发。所有配置通过 application.yml 完成。

常用配置属性

属性说明示例值
server.portHTTP 监听端口8080、0(随机端口)
server.address绑定网络地址127.0.0.1、0.0.0.0
server.servlet.context-path应用上下文根路径/student
server.tomcat.threads.maxTomcat 最大线程数200
server.tomcat.threads.min-spareTomcat 最小空闲线程10
server.tomcat.max-connections最大连接数10000
server.tomcat.connection-timeout连接超时60s
server.compression.enabled响应压缩开关true
server.http2.enabledHTTP/2 支持true(需配合 TLS)

切换容器的依赖方式

<!-- 默认:Tomcat(无需额外配置) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 切换为 Jetty:排除 Tomcat,引入 Jetty 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-jetty</artifactId>
</dependency>
<!-- 切换为 Undertow:高性能、低内存占用 -->
<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>

核心原理

内嵌服务器启动时序

Spring Boot 应用在 SpringApplication.run() 过程中,通过 ServletWebServerApplicationContext 自动探测并创建内嵌 Web 服务器。以下是关键时序:

时序解读:

  1. 当 Spring Boot 探测到类路径存在 ServletWebServerFactory(由 spring-boot-starter-web 引入)时,自动判定为 Web 应用类型。
  2. 在上下文刷新阶段,触发 onRefresh() 钩子,向容器索取 WebServerFactory Bean。
  3. TomcatServletWebServerFactory 负责实例化 Tomcat 对象,配置 Connector(端口、协议)、Host、Context。
  4. DispatcherServlet 被自动注册到 Servlet 容器中,映射路径为 /。
  5. 服务器启动后,应用进入就绪状态,即可接收 HTTP 请求。

三种容器的层次对比

选型建议:

  • Tomcat:默认选择,生态最成熟,社区资料最多。
  • Jetty:适合长连接、WebSocket 场景,线程模型更灵活。
  • Undertow:基于 XNIO 的非阻塞 IO,内存占用最低,吞吐量高,适合高并发微服务。

完整示例

场景说明

飞翔科技的学生成绩管理系统需要独立部署到一台测试服务器上。架构师白歌要求后端开发小崔:应用必须以可执行 JAR 运行,监听 8080 端口,上下文路径为 /student,且支持响应压缩。小崔需要验证内嵌 Tomcat 的启动效果。

操作前:无配置状态

# 操作前:application.yml(空文件或仅有数据库配置)
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/student_db
    username: root
    password: root

此时启动应用,Spring Boot 使用全部默认值:端口 8080、上下文路径 /、无压缩。访问 http://localhost:8080/ 直接命中根路径。

启动日志:

Tomcat started on port(s): 8080 (http) with context path ''

使用该特性的完整代码

小崔在 application.yml 中补充服务器配置:

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/student_db
    username: root
    password: root

server:
  port: 8080
  servlet:
    context-path: /student
  compression:
    enabled: true
    mime-types: application/json,application/xml,text/html
  tomcat:
    threads:
      max: 100
      min-spare: 10

业务代码无需任何改动。启动类保持标准写法:

package com.feixiang.student;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class StudentManagementApplication {
    public static void main(String[] args) {
        SpringApplication.run(StudentManagementApplication.class, args);
    }
}

操作后运行结果及分析

启动日志:

Tomcat started on port(s): 8080 (http) with context path '/student'
Started StudentManagementApplication in 2.456 seconds

验证端口监听:

$ curl http://localhost:8080/student/actuator/health
{"status":"UP"}

分析:

  1. server.port=8080 生效:Tomcat 在 8080 端口启动监听。
  2. server.servlet.context-path=/student 生效:所有端点前缀自动变为 /student,实现应用级隔离。
  3. server.compression.enabled=true 生效:返回大于阈值的 JSON/HTML 响应时自动使用 Gzip 压缩。
  4. server.tomcat.threads.max=100 生效:Tomcat 线程池上限被限制为 100,避免资源耗尽。

易错场景与面试考点

易错场景一:端口冲突导致启动失败

小崔在本地同时启动了两个 Spring Boot 服务,第二个应用报错:

Web server failed to start. Port 8080 was already in use.

错误处理:小崔直接修改代码中的 server.port 为固定值,但提交时不小心将这段配置推到了 Git,导致测试环境也用了非标准端口。

正确做法:开发环境使用临时命令行参数覆盖,不改动代码:

java -jar student-app.jar --server.port=8081

或在 application.yml 中利用随机端口做本地测试:

server:
  port: ${random.int[8080,8090]}

易错场景二:切换 Jetty 时未排除 Tomcat 导致冲突

<!-- 错误示范:同时存在 Tomcat 和 Jetty Starter -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

后果:类路径中同时存在两个 ServletWebServerFactory 实现(Tomcat 和 Jetty),Spring Boot 无法判断应使用哪个,启动时抛出 IllegalStateException: Multiple ServletWebServerFactory beans found。

正确做法:切换容器时必须使用 <exclusions> 排除默认的 spring-boot-starter-tomcat。

面试考点

Q:Spring Boot 内嵌 Tomcat 是如何启动的?

SpringApplication.run() 创建 ServletWebServerApplicationContext,在上下文刷新阶段通过 onRefresh() 方法从容器中获取 WebServerFactory Bean(如 TomcatServletWebServerFactory),由工厂创建并启动内嵌服务器,同时自动注册 DispatcherServlet。

Q:内嵌服务器和传统外置 Tomcat 有什么区别?

内嵌服务器的生命周期由 Spring 容器管理,随应用启停;应用与容器版本绑定在 JAR 中,一个应用一个进程。外置 Tomcat 多应用共享同一容器,版本由运维统一控制,部署需手动复制 WAR。

Q:server.port=0 有什么效果?

启动时由操作系统分配一个临时可用端口,适合并行测试或多实例启动。实际端口值可通过 Environment 或 @LocalServerPort 注入获取。

Q:Spring Boot 2.7.x 默认内嵌的是 Tomcat 几?

默认内嵌 Tomcat 9.x(对应 Servlet 4.0 规范)。若切换 Jetty 则对应 Jetty 9.4.x,切换 Undertow 则对应 Undertow 2.2.x。

上一页
章节导读:内嵌服务器与部署
下一页
Fat Jar