# Java程序员还需要学Tomcat吗

- Published: 2026-03-05
- Category: 随笔文章
- Canonical: https://liwenye.cn/Java%E7%A8%8B%E5%BA%8F%E5%91%98%E8%BF%98%E9%9C%80%E8%A6%81%E5%AD%A6Tomcat%E5%90%97/

> 这是公开文章的机器可读副本。引用时请链接上面的 canonical 页面。

---

## 1

很多 Java 程序员都有一个共同的困惑：Tomcat 到底还要不要学？

大家都知道 Tomcat 很重要，也知道 Spring Boot 默认内嵌了它。但如果你日常做的是 2B 项目，用户量不大，QPS 也不高，主要就是写接口、对接系统、处理数据——花大量时间去研究 Tomcat，真的有必要吗？

我最近梳理了一下这个问题，发现它背后牵出了一整条概念链：Web 服务器是什么，Servlet 容器是什么，Servlet 和 Controller 什么关系，Java EE 和 Jakarta EE 又是怎么回事。这些概念很多人似懂非懂，但只要顺着“Tomcat 要不要学”这个问题往下捋，它们就全串起来了。

## 2

先说结论：Tomcat 不需要深挖，但不能完全不懂。

如果你的项目是典型的 2B 系统，业务逻辑多，并发量低，那确实没必要把 Tomcat 当成主攻方向。你大概率不需要去读它的源码，不需要研究连接器的每个参数，也不需要深入 NIO 模型和线程池的实现细节。

但 Tomcat 不能完全忽略。因为 Spring Boot 只是把它“内嵌”了，不是把它“消灭”了。

你的应用仍然跑在 Tomcat 上面。HTTP 请求仍然要经过它，线程管理、连接管理、请求的生命周期，这些事情仍然由它负责。只不过你不再需要手动部署 war 包、手动配置 server.xml 而已。

换句话说，Tomcat 从“你要直接操作的东西”，变成了“你必须理解其存在的底座”。

所以更准确地说：Tomcat 不需要学到专家级，但至少要学到理解系统运行机制、能排查问题、能和别人有效沟通的程度。

## 3

要理解 Tomcat，先得搞清楚几个基本概念之间的关系。

很多人对 Tomcat 的第一印象是：它是一个 Web 服务器，负责接收 HTTP 请求，然后把请求转给 Java 应用。方向是对的，但可以再精确一点。

Tomcat 其实有两层身份。

第一层是 HTTP 服务器。这一层负责网络层面的事情：监听端口、建立连接、解析 HTTP 协议、管理 keep-alive、处理超时、把字节流读进来再写回去。

第二层是 Servlet 容器。这一层负责 Java 的事情：把 HTTP 请求包装成 Java 对象（`HttpServletRequest` 和 `HttpServletResponse`），然后按照一套标准规则调用应用代码，最后把结果写回给客户端。

也就是说，Tomcat 做的不只是“转发”，它做的是一整套从网络协议到 Java 对象的桥接工作。

## 4

说到 Servlet 容器，就必须解释一下 Servlet 到底是什么。

很多人把 Servlet 理解成“某个类”或者“某种老旧的写法”，其实不准确。Servlet 更准确的定义是：Java Web 应用暴露给容器调用的一套标准接口。

这里最容易搞反的一点是：不是 Servlet 去调用 Tomcat，而是 Tomcat 去调用 Servlet。

打个比方。你去餐厅吃饭，餐厅有一套点菜流程：你看菜单、选菜、告诉服务员。这个流程是餐厅定的，不是你定的。你作为顾客，只需要“实现”点菜这个动作就行了。

在 Java Web 世界里，Tomcat 就是餐厅，Servlet 就是你按照餐厅规则提供的那个“点菜动作”。容器掌握调度权，应用提供处理逻辑。这在软件工程里叫做“回调”——运行时由平台来调你，而不是你主动去调平台。

一句话总结：Servlet 是应用暴露给容器的入口接口，Tomcat 是负责运行并调用这些入口的容器实现。

## 5

理解了 Servlet，就可以来看 Spring MVC 做了什么。

在 Spring MVC 时代，我们不再手写一堆 Servlet 了。所有请求都会先进入一个叫 `DispatcherServlet` 的东西。

很多人第一次看到这个名字会疑惑：它也只是一个 Servlet 啊，凭什么整个系统的请求都给它？

原因在于它的设计模式。`DispatcherServlet` 是一个“前端控制器”（Front Controller）。传统模式下，一个 URL 对应一个 Servlet。而 `DispatcherServlet` 把所有请求先收进来，然后在框架内部根据 URL、HTTP 方法、参数、Header 等信息，再分发到具体的 Controller 方法上。

所以在 Spring MVC 里，真正面对 Tomcat 的不是你写的业务代码，而是 `DispatcherServlet`。你的 `@RestController`、`@Controller` 方法，其实不是 Servlet，它们是 `DispatcherServlet` 内部再分发出来的业务处理单元。

这就是为什么很多 Java 开发者“感觉不到 Servlet 的存在”。你平时写的是 Controller，但 Controller 的下面仍然是 Servlet 模型，只是被 Spring 封装起来了。

## 6

那么，在 Spring 出现之前，Java Web 是怎么工作的呢？

最原始的写法是这样的：你自己写一个类，继承 `HttpServlet`，重写 `doGet`、`doPost` 方法。你要自己从 `HttpServletRequest` 里取参数，自己解析输入流，自己设置响应头，自己往 `HttpServletResponse` 里写内容。然后在 `web.xml` 里配置 URL 和 Servlet 的映射关系。

后来 Servlet 规范升级了，可以用 `@WebServlet` 注解来做映射。再后来，Spring MVC 出现了，你只需要用 `@RequestMapping` 就能把请求映射到一个普通的 Java 方法上。

你会发现，这么多年 Java Web 开发的主线从来没变过：请求匹配到一个处理器，执行逻辑，返回响应。

变化的只是抽象层级。早期你直接操作 Servlet，后来用注解注册 Servlet，再后来用 Spring 把请求映射到方法。映射的本质没变，只是越来越细、越来越方便。

## 7

所以 Spring MVC 到底厉害在哪里？很多人说“注解比 XML 方便”，这个说法没错，但远远不够。

Spring MVC 真正做的事情是：把 Web 编程从“类级别”提升到了“方法级别”。

在 Servlet 时代，一个 URL 通常对应一个类。你需要在类里面自己区分不同的逻辑。到了 Spring MVC，映射粒度细化到了方法级别。你可以很自然地写出 `GET /orders/{id}`、`POST /orders`、`PUT /orders/{id}`，每个接口就是一个普通方法。

除此之外，Spring MVC 还系统性地接管了大量脏活累活。

以前你要自己从 request 里取参数、自己判断类型、自己解析 JSON、自己设置状态码。现在用 `@RequestBody`、`@RequestParam`、`@PathVariable` 就能自动完成。

以前一个异常抛出来，怎么返回给前端要自己控制。现在用 `@ControllerAdvice` 就能统一处理。

以前你想给所有请求加日志、鉴权、审计，要自己写 Filter 或者硬编码在 Servlet 里。现在有 Filter、Interceptor、AOP 等多种拦截能力可以组合使用。

Spring 的本质不是“更方便”，而是把 Web 开发从底层协议编程，推进到了更接近业务模型的层面。

## 8

理解了 Tomcat 和 Spring 的关系之后，还剩一个经常让人困惑的概念：Java EE。

很多人听到 Java EE 就觉得它很抽象，像是某种“大而空”的历史名词。其实用工程师熟悉的话说，它就是一份接口合同。

所谓“规范”，就是一份公开的标准文档，规定了要有哪些接口、哪些类、它们该怎么表现、生命周期是什么、异常怎么定义。规范本身不是一个能运行的软件，它是一套标准。然后不同的项目去实现这套标准。

打个比方，4G 标准规定了通信协议和行为方式，不同厂商去做基站和手机。只要遵循标准，就能互通。Java 世界里的规范也是这样：规范负责定义“应该怎样”，实现负责回答“具体怎么做”。

Java SE 是 Java 的标准版，包含语言、JVM、基础类库。Java EE 则是建立在 Java SE 之上的一组面向企业开发的标准能力，比如 Servlet、JPA、Bean Validation、JAX-RS 等等。

它不是“更强大的 JDK”，也不是什么“企业版安装包”。它是一组标准接口的集合。

所以你下载一个 JDK，拿到的是 Java SE 的实现。而 Java EE 里的那些能力，是由 Tomcat、Hibernate 这些项目来实现的。Servlet 规范由 Tomcat 实现，JPA 由 Hibernate 实现，Validation 由 Hibernate Validator 实现。Spring 则在这些实现之上，再做了更高级的封装。

## 9

这几年升级 Spring Boot 项目的人，肯定都遇到过一个变化：代码里的 `javax.*` 变成了 `jakarta.*`。

比如 `javax.servlet` 变成了 `jakarta.servlet`。

这个变化的原因不是技术上有什么大突破，而是治理权发生了变化。

Java EE 原来归 Oracle 管，后来 Oracle 把它转移到了 Eclipse 基金会。但 `javax` 这个命名空间的使用权没有一起转移。Eclipse 基金会拿到了规范的演进权，却无法继续使用 `javax` 这个名字。

于是只能做一次断代式迁移：Java EE 改名为 Jakarta EE，命名空间从 `javax.*` 全面转向 `jakarta.*`。

这就是为什么 Spring 6 / Spring Boot 3 升级时，最明显的变化不是某个功能特性，而是一大堆包名从 `javax` 变成了 `jakarta`。Tomcat 10 及之后的版本，也全面站在了 Jakarta 体系上。

## 10

理解了这条线之后，很多人还会追问一个问题：Tomcat、Spring 这些项目，为什么能活这么多年？

答案不是“没有挑战者”，而是它们积累了大量的稳定性和生态惯性。

Tomcat 之所以难以被动摇，不是因为它技术上绝对领先，而是因为它在企业级 Java Web 场景里长期扮演了一个非常稳定、非常可预期的角色。对于大量低并发、重业务、重兼容的系统来说，替换 Tomcat 带来的收益，远远小于替换它带来的风险。

Spring 也类似。它的优势不只是功能多，而是在依赖注入、Web、事务、数据访问、测试这一整套企业开发体验上，形成了巨大的完整性。

这些项目能持续演进，也跟治理方式有关。Tomcat 属于 Apache 基金会，有成熟的项目治理、发布机制和安全响应体系。Spring 则是公司主导型开源，由稳定的核心团队持续投入。

真正能活很多年的基础设施，不只是代码写得好，还得有持续演进的组织能力。

## 11

最后回到最初的问题。

对一个做 2B 项目、低 QPS、以业务开发为主的 Java 程序员来说，Tomcat 最合适的学习深度不是“专家级”，而是“理解运行机制级”。

你需要知道的是这些事情：

Tomcat 既是 HTTP 服务器，也是 Servlet 容器。Servlet 是应用暴露给容器调用的标准入口。Spring MVC 没有绕开 Servlet，而是通过 `DispatcherServlet` 把 Servlet 模型进一步抽象成了 Controller 模型。从过去到现在，Web 开发的本质都是请求映射，只是映射粒度和工程能力越来越强。Java EE / Jakarta EE 是一组企业标准规范，Tomcat、Hibernate 是这些规范的实现者。

理解到这个层面，你就具备了非常扎实的底座认知。

你不一定会去调 Tomcat 的线程参数，不一定会去研究连接器实现，但你会知道一个请求是怎样走进系统的，会知道 Controller 之下其实还有 Servlet，会知道为什么升级 Spring Boot 3 时包名从 `javax` 变成了 `jakarta`，也会知道规范、框架、容器和业务代码在整个体系中各自扮演什么角色。

真正高价值的成长，从来不是把所有底层细节都变成自己的主战场，而是知道哪些东西应该深挖，哪些东西理解其本质后适可而止。

Tomcat 就属于后者。它不是一个“成熟到可以忽略的老工具”，Servlet 也不是一个“面试里偶尔会问到的老名词”。它们一直都在，只是被现代框架包裹得更优雅了。

理解这些底层关系，不是为了让你回到老时代手写 Servlet，而是为了让你在今天写 Spring Boot 业务代码时，知道自己站在怎样一套技术演进链条之上。
