简介:Apache Tomcat 7.0.108 是面向 Java Web 开发与运维人员的经典 Servlet 容器版本,适合部署 JSP、Servlet 及构建本地调试环境。压缩包内含完整的 apache-tomcat-7.0.108 主目录,共 640 个文件、约 10.38MB,文件类型以 html、class、java、jsp 为主,并包含 bat/sh 启停脚本、xml 配置文件、jar 依赖库及 war 示例包,足以覆盖 Tomcat 启动、配置和 Web 应用发布的完整链路。已有 628 人学习下载,对初学者快速搭建开发环境、运维人员排查部署问题都很有帮助。包内目录结构标准清晰,bin、conf、lib、webapps、logs 等一应俱全,解压后即可参考设置 CATALINA_HOME 环境变量,通过 startup/shutdown 脚本管理服务;既可将 WAR 文件放入 webapps 实现自动部署,也可在 server.xml 中配置 Context 指定应用路径。该版本稳定、体量小,还附带 logs 日志与 manager 管理入口相关资料,是理解 Tomcat 运行机制与日常排错的实用工具。 如果你找过 Tomcat 的历史版本,大概率在 Apache 官网的 archive 列表里见过这个文件名:tomcat-7.0.108.zip。我电脑里至今还留着一份,说实话不是怀旧,是手头真的有几个老系统还在靠它跑。这个版本大概处于 Tomcat 7 系列的收尾阶段,之后 7.x 就慢慢进入维护末期了,所以它既承载了不少生产环境的稳定运行经验,也浓缩了那个年代 Java Web 项目部署的一整套标准动作。
这篇东西不是单纯讲“怎么解压、怎么点启动”,我想把围绕这个压缩包展开的事一次聊透:版本选型逻辑、JDK 匹配、目录结构、war 包部署、启动排错,以及那些你在 jstack 里看到却不知道从哪来的线程。适合正在维护老旧项目的人看,也适合刚接触 Tomcat、想搞清楚“为什么别人启动那么快,我启动这么慢”的新手。
1. 这个压缩包背后的版本定位与选型逻辑
1.1 版本号里的信息量:7.0.108 代表什么
Tomcat 的版本号跟大多数软件一样,走的是“主版本.次版本.增量版本”的路子。7 是主版本,0 是次版本,108 是持续迭代的补丁号。7.0.x 系列的整个生命周期里,补丁版本一直在推送安全更新和 bug 修复,即便功能层面早就定型了。到了 7.0.108 这种阶段,新特性基本别指望,但稳定性反而是最让人放心的。
很多人会把 Tomcat 和 Java 的版本错位理解,以为 Tomcat 越新就必须配越新的 JDK。其实这套对应关系相当严格:Tomcat 7 的字节码基于 Java 6 编译,但官方推荐跑在 Java 7 或 8 上。它完全跑不了 Java 11 以上的运行时,更别说 Java 21 了。你要是拿 Java 21 去启动 Tomcat 7,直接抛 UnsupportedClassVersionError,启动即失败。
1.2 为什么到今天我还在用 Tomcat 7
不是情怀驱动,是存量系统太庞大了。很多企业内部的老项目,代码基于 Servlet 3.0 规范写,用的还是 JSP + JSTL 那一套,当年上线时选型就是 Tomcat 7。业务跑得挺稳,领导不会因为你“想升级”就给排期,毕竟升级可能引入不兼容问题,风险比收益大得多。
还有一个现实原因是 JDK 版本锁死了。老项目很多跑在 JDK 8 上,有的甚至被迫停留在 JDK 7,Tomcat 7 是为数不多能在这些老旧 JDK 环境下稳定运行的选择。不是它多先进,而是它跟那个时代的 Java Web 技术栈天然契合。只要你不需要 HTTP/2、不需要 WebSocket 的高级特性、不需要 Servlet 4.0 以上的 API,Tomcat 7 完全够用。
1.3 zip 包、exe 安装包和源码包怎么选
Apache 官网给 Windows 用户提供了 32/64 位的 zip 包和 exe 安装包。我的建议是无脑选 zip 包,原因很简单:它不需要写注册表,不需要管理员权限,解压到你想要的目录就能跑,卸载时直接删文件夹。exe 安装版会注册 Windows 服务,适合服务器托管场景,但本地开发用反而碍事。
源码包是给想研究 Tomcat 内部实现、二次开发的人准备的。绝大多数人用它只是为了部署应用,不需要看源码。下载时记住一个原则:binaries 目录下的是可运行发行版,src 目录下的是源码,别下错。zip 包内部结构都一样,解压后你会看到 bin、conf、lib、logs、temp、webapps、work 这七个标准目录,后面部署全跟它们打交道。
2. 安装配置前必须搞清楚的几件事
2.1 JDK 版本匹配与 JAVA_HOME 配置
Tomcat 本身是 Java 程序,它启动靠的是java命令,所以第一件事是让系统能找到 JDK。Tomcat 7 配 JDK 8 是最常见的组合,如果你是纯开发学习,JDK 8 就够;如果有老系统用 JDK 7,也别慌,Tomcat 7 照样支持。
环境变量说起来只有两个关键的:
JAVA_HOME:指向 JDK 安装根目录,不是 bin 目录CATALINA_HOME:指向 Tomcat 解压后的根目录
PATH 里建议加上%JAVA_HOME%\bin,这样你在命令行敲java -version能直接验证。
注意:
CATALINA_HOME配错是新手最常见的启动失败原因。很多教程让人配TOMCAT_HOME,其实 Tomcat 的官方脚本只认CATALINA_HOME,TOMCAT_HOME是兼容性残留。两个都配也行,但必须以CATALINA_HOME为准。
2.2 目录结构:每个文件夹是干什么的
zip 包解压后的目录不是随便放的,每个目录都有明确职责:
bin:存放启动和关闭脚本,Windows 下是.bat,Linux 下是.shconf:核心配置目录,server.xml是主配置文件,web.xml是全局 Servlet 配置,context.xml管全局 JNDI 资源lib:Tomcat 运行时的公共 Jar 包logs:日志目录,启动异常排查基本都在这里temp:临时文件目录,Tomcat 运行时会往这里写临时文件webapps:部署目录,war 包或解压后的应用都放这里work:JSP 编译后的 class 文件缓存目录
很多人在部署时遇到“页面改了不生效”,其实就是没理解work目录的作用。JSP 第一次被访问时会编译成 Servlet,缓存在work/Catalina下。你改了 JSP,Tomcat 会检测到变化重新编译,但如果你直接替换了整个应用目录,旧的编译缓存有时会捣乱,删掉work目录下的对应目录再重启往往能解决。
2.3 端口、连接器和默认行为
conf/server.xml里最核心的是 Connector 配置。默认 HTTP 连接器监听 8080 端口,协议是HTTP/1.1。你访问http://localhost:8080能看到那只猫,就是因为 Connector 把请求交给了默认的 ROOT 应用。如果你装了多个 Tomcat 实例,必须改端口,不然第二个实例启动会报Port already in use。
我实际踩过的坑是:修改端口后忘了改 shutdown 端口。server.xml里还有一个 8005 端口,是用来接收 shutdown 命令的。两个 Tomcat 实例如果 8005 冲突,你敲shutdown.sh可能把另一个实例关掉。所以多实例部署时,HTTP 端口、AJP 端口(默认 8009)、shutdown 端口都要改全。
3. 安装、启动与项目部署实战
3.1 Windows 下安装启动:两步走
解压 zip 包到指定目录,比如D:\tomcat-7.0.108,配置好JAVA_HOME,然后双击bin\startup.bat,在一个新弹出的命令行窗口里看到Server startup in [多少毫秒],就说明启动成功了。
不要直接双击tomcat7w.exe——那是给 exe 安装版用的 Windows 服务管理器,zip 包里没有这个文件。zip 包只需要关注startup.bat和shutdown.bat。
需要提醒的是:启动后那个黑窗口不要关。它不是“多余的 DOS 窗口”,而是 Tomcat 的控制台,
System.out和System.err都会输出到这里。很多人看它一直不动就手动关掉,结果是直接把 Tomcat 进程杀了。想看完整日志,看logs/catalina.<日期>.log更靠谱。
启动完成后验证三步走:
- 浏览器访问
http://localhost:8080 - 看到 Tomcat 默认首页,说明 Web 层正常
- 命令行执行
netstat -ano | findstr 8080,能查到 java 进程监听该端口
3.2 Linux 下安装启动:systemd 托管方式
Linux 服务器上我一般不直接跑catalina.sh run,而是把 Tomcat 配成 systemd 服务,这样开机自启、崩溃重启都能自动搞定。比如新建/etc/systemd/system/tomcat.service,大概配置如下:
[Unit] Description=Apache Tomcat 7 After=network.target [Service] Type=forking Environment=JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 Environment=CATALINA_HOME=/opt/tomcat-7.0.108 Environment=CATALINA_BASE=/opt/tomcat-7.0.108 ExecStart=/opt/tomcat-7.0.108/bin/startup.sh ExecStop=/opt/tomcat-7.0.108/bin/shutdown.sh User=tomcat Group=tomcat Restart=on-failure [Install] WantedBy=multi-user.target配置好后执行systemctl daemon-reload,再用systemctl start tomcat启动。这里有个细节:Tomcat 启动脚本是 fork 出子进程的,所以Type必须是forking,如果你配成simple,systemd 会认为服务启动失败。
另外,Linux 下启动时报Permission denied是很常见的,多半是 bin 目录下的 .sh 脚本没有执行权限。执行chmod +x /opt/tomcat-7.0.108/bin/*.sh即可。还有一个坑是生产服务器上内存配置,默认的catalina.sh没有给 JVM 指定堆大小,高并发下很容易 OOM。建议在bin/setenv.sh(没有就新建)里显式配置:
export JAVA_OPTS="-Xms1024m -Xmx2048m -XX:MaxPermGen=256m"注意 Tomcat 7 跑在 JDK 8 上时,PermGen参数还有效,但到了 JDK 8 的后期版本已经忽略MaxPermGen,改用MetaspaceSize。老项目如果还没迁移元空间,看到这个参数也别慌,稳妥起见两个都写上,Tomcat 7 配 JDK 8 不会报错。
3.3 war 包部署的三种路径
war 包部署是 Tomcat 最常见的应用场景。它本质上是一个 zip 格式的 Web 应用压缩包,里面包含WEB-INF目录和静态资源。部署方式有三种:
第一种,直接复制 war 包到webapps目录,启动时 Tomcat 会自动解压并部署。这是最省事的,适合开发和测试环境。Tomcat 7 默认配置了autoDeploy=true,你在运行状态下拷入 war 包,它也会热部署。
第二种,不复制文件,只在conf/server.xml的 Host 节点下配置 Context,指向外部目录。这种适合把应用和 Tomcat 分开管理的场景:
<Context path="/myapp" docBase="/data/apps/myapp" reloadable="true" />这样应用代码可以放在 Tomcat 之外,方便版本管理和备份。
第三种,结合 Maven 插件远程部署。Tomcat 7 的 manager 应用支持在pom.xml里配置tomcat7-maven-plugin,然后执行mvn tomcat7:deploy直接把项目发布到远程服务器。这种方式的优点是干净利落,不用手动拷贝 war 包。
从实际运维角度看,我推荐第一种加第三种组合:本地开发用 Maven 插件一键部署,生产环境用自动化脚本拷贝 war 包再 restart。
3.4 在 IDEA 和 Eclipse 里配置 Tomcat
smart tomcat是 IDEA 的插件,也是不少新人用了就回不去的工具。它解决的核心痛点是:不用手动部署 war 包,直接在 IDEA 里点一下就能启动。安装后在 Run Configuration 里指定 Tomcat 目录和部署的 artifact 即可。
IDEA 2024.2 还支持远程调试 Tomcat。方式是远程 Tomcat 启动时加上 JVM 参数:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005本地 IDEA 创建一个 Remote JVM Debug 配置,Host 填远程服务器 IP,Port 填 5005,就能断点调试远程部署的应用。注意:生产环境千万别开这个,等于脱了裤子跑,任何人连上 5005 就能控制你的 JVM。
Eclipse 配置思路也差不多,在 Servers 视图里新增 Tomcat 7,指定安装目录和 JDK 即可。如果你为这个问题查过 CSDN,大概率是卡在了 Tomcat 版本和 IDE 版本不匹配上,Eclipse 2020 以后版本对 Tomcat 7 的支持没问题,但老版本的 Eclipse 需要装对应适配器。
4. 高频故障复盘:从启动失败到线程排查
4.1 启动慢:可能不是 Tomcat 的问题
很多新手第一次启动 Tomcat,发现卡在类似于Deploying web application archive这一步,一等就是几十秒甚至几分钟。网上搜到的答案多半是“配置 JRE 随机数生成器”,原因是 JVM 在 Linux 上默认用/dev/random作为熵源,熵池不够用时会阻塞。解决办法是在 catalina.sh 里加:
JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom"但我想提醒一句:这是常见原因,却不是唯一原因。实际工作中我还遇到过场景是应用里加载了数据库连接池,但数据库连不通,连接超时时间设置得太长,导致启动过程卡在那里。所以启动慢要结合日志看,不是日志一停就怪随机数。
4.2 端口占用:报错信息一眼能认出
启动时如果看到java.net.BindException: Address already in use,基本就是端口被占了。Linux 下用netstat -tlnp | grep 8080看哪个进程占用了,Windows 下用netstat -ano | findstr 8080。
我曾经遇到一个诡异情况:8080 端口没有被占用,但 Tomcat 还是启动失败。后来发现是 8005 端口被别的进程占了,日志里抛出的堆栈是关于 shutdown 端口的,不看全堆栈根本发现不了。所以排查端口问题时一定要把server.xml里涉及到的端口都查一遍。
4.3 APR 提示:不是错误,不用焦虑
日志里经常出现一行:
The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path好多人第一次看到还以为是缺少什么关键组件,去网上找解决办法。这句话的本质是:Tomcat 想尝试加载 APR 本地库(用于提升静态文件处理和 SSL 性能),但没找到,所以自动退化到纯 Java 的 BIO/NIO 模式。对大部分业务场景来说,性能差异根本感知不到,可以忽略。
如果你强迫症犯了,也可以安装libtcnative库。但从我的实践看,Tomcat 7 搭配 JDK 8 的 NIO 连接器,应付常规 Web 业务绰绰有余,没必要在这个版本上折腾 APR。
4.4 jstack 里的神秘线程:RMI TCP Connection 从哪来的
用jstack <pid>查看线程快照时,你大概率会看到一堆RMI TCP Connection线程,很多人以为这是 Tomcat 的连接处理线程。其实不是。这些线程来自 JVM 的 JMX 管理功能,是 JVM 自己启动的。Tomcat 的catalina.sh里如果配置了 JMX 相关参数,JVM 就会自动创建 RMI 连接器,用于远程监控。
所以,Tomcat 默认情况下启动一堆“RMI TCP Connection”线程是正常现象,尤其当你的脚本里设置了com.sun.management.jmxremote相关参数时。如果实在想关掉,可以在 JVM 参数里加-Dcom.sun.management.jmxremote=false。不过一般不建议这么做,因为生产环境看 JVM 内存和 GC 日志还得靠 JMX 呢。
4.5 快速排查问题速查表
整理一份我在群里回答过无数次的排查表,按优先级排序:
| 症状 | 典型原因 | 处理手段 |
|---|---|---|
| 启动后立即退出,没有日志 | JAVA_HOME 没配好 | 执行java -version验证 |
| 启动到一半卡住 | 应用初始化连接池超时 | 检查数据库配置、看 catalina.log 完整日志 |
| BindException | 端口被占用 | 换端口或杀占用进程 |
| 404 访问不到应用 | war 包没成功解压 | 检查 webapps 目录、日志中的部署记录 |
| 页面能打开但 CSS/JS 404 | 应用路径配置错误 | 检查 Context path 和前端资源引用 |
| Java 11+ 启动报 UnsupportedClassVersionError | Tomcat 7 不支持新 JDK | 换成 JDK 8 或升级 Tomcat |
| 远程调试连不上 | suspend 参数配置错误 | 确认address=5005且防火墙放行 |
| 用 jacoco 统计远程代码覆盖率不生效 | agent 参数没加到要统计的 JVM 上 | 在 Tomcat 的 setenv.sh 里加-javaagent:/path/jacocoagent.jar=includes=*,output=tcpserver,port=6300,address=*,再重启 |
4.6 关于“启动脚本强制关闭”的一个经验
Linux 下如果shutdown.sh关不掉 Tomcat,最常见的原因是进程卡死或线程池里有任务没结束。这时候别直接kill -9,先尝试kill -15 <pid>(优雅终止)。不行再看完整线程快照,确认到底是什么线程阻塞了 shutdown。
我习惯的做法是给 Tomcat 的 shutdown 配置一个超时检查:先杀进程,等待 10 秒,然后ps -ef | grep java确认真的没了,再启动新实例。盲目kill -9可能导致正在处理的请求被硬断,数据一致性受影响的锅还得背在自己头上。
5. 什么时候该离开 Tomcat 7,升级路怎么走
5.1 版本代差一览
顺手整理一个常见版本对比,方便你对照自己的项目做决定:
| 版本 | 最低 JDK | Servlet 规范 | 适用场景 |
|---|---|---|---|
| Tomcat 7 | JDK 6 | Servlet 3.0 | 存量老系统、JDK 8 以下环境 |
| Tomcat 8.5 | JDK 7(推荐 8) | Servlet 3.1 | 老项目轻微升级、NIO 优化 |
| Tomcat 9 | JDK 8 | Servlet 4.0 | 新项目默认选择、HTTP/2 |
| Tomcat 10 | JDK 8+(推荐 11) | Jakarta Servlet 5.0(包名变了!) | 只适合新项目 |
| Tomcat 11 | JDK 17 | 版本更高 | 用最新规范的新项目 |
重点提醒:Tomcat 10 起包名从javax.servlet.*改成jakarta.servlet.*,老代码直接搬过去是编译不过的。所以老项目如果决定换版本,推荐目标锁定在 Tomcat 9,改动量小很多。
5.2 老项目升级的实际操作建议
升级之前先想清楚动机。如果你只是因为“Tomcat 7 老了”就想升级,我劝你三思。但如果你遇到了以下几个情况,升级是值得的:
- 项目需要支持 HTTP/2,7 做不到
- 安全扫描报告里出现 Tomcat 7 的已知漏洞,而且官方不再回补
- 团队强制统一 JDK 版本,比如全部切到 17,那 Tomcat 7 只能被淘汰
升级路径上最大的阻力往往不是 Tomcat 本身,而是应用里的旧依赖。比如一些老框架带的javax.servlet-api版本过低,换到 Tomcat 9 后反而会出现冲突。我见过最省心的做法是:先把应用在 Tomcat 9 上跑起来,看日志报错,逐个修掉依赖冲突,最后再做回归测试。别追求一步到位上 Tomcat 10,那个jakarta包名迁移的工作量,够一个团队忙一周。
5.3 关于 Spring Boot 内置 Tomcat 的一个补充
现在很多新项目用的是 Spring Boot,它已经内置了 Tomcat。有些基于 Spring Boot 的老项目(比如若依这类前后端分离框架)配置文件里直接 exclude 掉内置 Tomcat,用外置 Tomcat 部署 war 包。
如果你是自己写 Spring Boot 项目,想去掉内置 Tomcat,只需要在pom.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>同时把启动类继承SpringBootServletInitializer并重写configure方法,打 war 包丢给外置 Tomcat。但说实话,除非是运维强制要求统一用外置容器,否则我还是推荐内置 Tomcat 直接跑 jar,部署简单、版本可控、升级方便。
6. 写在最后的一些真实体会
把 Tomcat 7.0.108 这份压缩包从解压到排错到升级规划完整走一遍之后,我的感受是:技术选型从来没有“老的”就一定是“坏的”这种道理。Tomcat 7 之所以到现在还有人找、还有人问,是因为它背后站着海量跑了好多年的业务系统,那些系统的稳定性早就被验证过了。升级与否,根本不是技术的较量,而是投入产出比的计算。
如果你只是学习 Java Web,没必要非装 Tomcat 7,直接上 Tomcat 9 更省心。但如果你接手了老项目,手头正好有这个 zip 包,别慌,按我上面写的路径走一遍:先确认 JDK 版本,再配置环境变量,看目录结构,部署 war 包,遇到问题对着排查表一步步来,大概率能搞定。最后,真正需要升级的时候,也别恋战,存量系统里跑得稳是一回事,停更之后的漏洞修复缺失又是另一回事,该走就得走。
本文还有配套的精品资源,点击获取