1.3 版本地图:从 JServ 到 Jakarta EE 本节摘要:Tomcat 的版本线是"规范级别的地图"而非产品编号——每个大版本绑定一代 Servlet 规范与一个 Java 最低版本,而 Tomcat 10 的 jakarta 包名空间切换是二十多年里最硬的一次分界。本节用一张演化时间线与两张对照表讲清版本、规范、Java 版本三者的锁定关系,并给出新旧项目的选型决策依据与迁移要点。 承接 1.2 的生态定位:知道了 Tomcat 站在哪一层,还要知道这条管道演化到第几代。本节是全册的"时间坐标",后续章节的配置示例默认基于 9 与 10.1 两条主流线,此处把它们的差异一次说透。
本节摘要:Tomcat 的版本线是"规范级别的地图"而非产品编号——每个大版本绑定一代 Servlet 规范与一个 Java 最低版本,而 Tomcat 10 的 jakarta 包名空间切换是二十多年里最硬的一次分界。本节用一张演化时间线与两张对照表讲清版本、规范、Java 版本三者的锁定关系,并给出新旧项目的选型决策依据与迁移要点。
承接 1.2 的生态定位:知道了 Tomcat 站在哪一层,还要知道这条管道演化到第几代。本节是全册的"时间坐标",后续章节的配置示例默认基于 9 与 10.1 两条主流线,此处把它们的差异一次说透。
Tomcat 的前身是 Sun 的 JServ,1999 年作为 Jakarta 项目的一部分开源,2005 年成为 Apache 顶级项目。此后的主线很清晰:跟着 Servlet 规范走。Servlet 2.5 时代(Tomcat 6)奠定了大家熟悉的 web.xml 写法;Servlet 3.0(Tomcat 7)带来注解配置与异步支持;Servlet 3.1(Tomcat 8)加入非阻塞 IO;Servlet 4.0(Tomcat 9)实现了 HTTP/2。真正的分水岭出现在 Tomcat 10:Java EE 从 Oracle 移交 Eclipse 基金会后更名 Jakarta EE,包名空间从 javax 换成 jakarta——这不是重命名那么简单,它意味着所有编译期依赖都要换坐标重编译。

第一张表把主流版本线与规范级别钉死,这张表值得抄进你的笔记本。
| Tomcat 版本 | Servlet 规范 | 包名空间 | 最低 Java | 状态 |
|---|---|---|---|---|
| 8.5 | 3.1 | javax | 7 | 维护收尾 |
| 9.0 | 4.0 | javax | 8 | 长期维护 |
| 10.0 | 5.0 | jakarta | 8 | 被 10.1 取代 |
| 10.1 | 6.0 | jakarta | 11 | 当前主流 |
| 11.0 | 6.1 | jakarta | 17 | 新一代线 |
第二张表回答"我的应用能不能搬过去"。迁移的本质是编译期依赖切换,判断依据就一条:所有涉 Servlet API 的依赖是否提供了 jakarta 版本。
| 你的处境 | 建议 |
|---|---|
| 新项目,Java 17,Spring Boot 3 | 直接 10.1 或 11,无需犹豫 |
| 新项目,被迫留在 Java 8 | 9 是终点,规划升级路线而非死等 |
| 遗留系统,依赖大量 javax 老包 | 留在 9,用迁移工具评估后再动 |
| 想平滑迁移 | 先用 Eclipse 提供的迁移工具改写字节码,再逐步换源码依赖 |
同一个"输出一段话"的 Servlet,在两条版本线上长这样。先是 Tomcat 9 的写法。
// Tomcat 9:javax 包名空间 import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.setContentType("text/plain;charset=UTF-8"); resp.getWriter().println("hello from javax line"); } }
再是 Tomcat 10.1 的写法,注意 import 一行之差。
// Tomcat 10.1:jakarta 包名空间 其余逻辑完全一致 import java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { resp.setContentType("text/plain;charset=UTF-8"); resp.getWriter().println("hello from jakarta line"); } }
把 javax 版的字节码直接丢进 Tomcat 10,启动不报错,访问时抛 ClassNotFound 一族的异常——类加载器在 jakarta 命名空间里找不到 javax.servlet.http.HttpServlet。这是迁移期最常见的故障形态,特征极其鲜明:部署成功、一访问就 500,栈里必带 servlet 字样。
配置描述符的版本声明也随规范走。9 的 web.xml 头部声明 version 为 4.0 且指向 javaee 命名空间,10.1 则是 6.0 加 jakarta 命名空间,抄旧模板时这个头不改,某些校验严格的组件会拒绝启动。
全景、生态、时间三张图到此集齐,装备检查可以开始——第 2 章把 Tomcat 装起来,读懂那张名为 server.xml 的配置地图。