Java程序员还需要学Tomcat吗

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 对象(HttpServletRequestHttpServletResponse),然后按照一套标准规则调用应用代码,最后把结果写回给客户端。

也就是说,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,重写 doGetdoPost 方法。你要自己从 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 /ordersPUT /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 业务代码时,知道自己站在怎样一套技术演进链条之上。