Tomcat 7.0.108 部署与调优:遗留系统的稳定运行之道
简介Tomcat 7.0.108 是 Apache 开源的 Java Servlet 容器稳定版本面向 Java Web 开发初学者与部署运维人员解决本地运行 JSP/Servlet 项目、配置虚拟主机及发布 WAR 包等常见需求。压缩包共 640 个文件约 10.38MB除核心 bin/conf/lib/webapps 等目录外还包含 228 个 html 页面、106 个 class 文件、78 个 java 源码、58 个 jsp 页面及若干 jar、xml 配置便于对照学习目录结构与默认应用。内置的 apache-tomcat-7.0.108 目录为完整解压版可直接设置 CATALINA_HOME 后启动使用。已有 628 人学习下载。通过分析 webapps 下的示例工程、conf/server.xml 配置及 bin 脚本可以快速掌握 WAR 部署、端口修改、日志查看与 manager 管理台用法适合在本地搭建轻量级 Java Web 调试环境。 一个老项目的部署文档里躺着一行下载链接tomcat-7.0.108.zip。看到这个文件名懂的人大概会心一笑——这个版本早就不再更新但不少公司的线上系统还在用它跑着JSP页面和内部接口。它属于 Apache Tomcat 7.x 系列的最终版2019 年 11 月发布之后官方就把 7.x 划入了 EOL 名单。放在今天来看你下载它大概率不是为了追新而是要复现某个历史环境、接手一个老系统或者单纯就是教程里指定了这个版本号。不管你是刚学 Java Web 的小白还是被老项目“折磨”的维护者这篇内容都按我实际操作的经验来讲从版本定位、解压安装、IDEA 调试到启动慢的坑、线程模型的误区再到日常排查。目标就一个——让你拿到这个 zip 之后能少搜几页资料直接把东西跑起来。1. 版本定位与选型判断先搞清楚 7.0.108 是什么1.1 一个压缩包背后的技术规格tomcat-7.0.108.zip是 Tomcat 7.x 系列的最后一个版本包。这里的 7.0 是大版本108 是维护版本号。它在功能上实现了 Servlet 3.0、JSP 2.2、EL 2.2 和 WebSocket 1.1对应 Java EE 6 Web Profile 的一部分。放到今天看这些规范不算新但它支撑起了无数遗留系统的日常运转。后面再没有 7.0.109 了也不会有。Tomcat 官方对 7.x 的维护在 2021 年 3 月正式截止之后发现的漏洞不再出补丁。这意味着如果你把它用在公网环境需要考虑风险如果是内网系统、开发调试、比赛题目、课程设计它反而因为稳定、轻量、资料多成了很省心的选择。这个 zip 包本身是跨平台的Windows、Linux、macOS 都能解压使用内部结构和 tar.gz 包完全一样并不像 Windows 安装版那样会写注册表、注册系统服务。它解压之后就能跑这也是很多人喜欢用 zip 版的原因——绿色、干净、不污染系统删的时候直接删文件夹就行。1.2 JDK、Maven、Spring 版本怎么匹配才不闹心老项目最常见的组合是 JDK 8 Tomcat 7 Spring 4.x如果项目里用了 Spring Boot 1.x它内嵌的也往往是 Tomcat 7 或 8。下面是我整理的一个匹配参考表列的是实际验证过的稳妥组合Tomcat 版本Servlet 规范JDK 建议Spring 版本建议7.0.x3.0JDK 7 / 8Spring 3.x / 4.x8.5.x3.1JDK 8Spring 4.x / 5.x9.0.x4.0JDK 8 / 11Spring 5.x10.1.x6.0JDK 11 及以上Spring 6.x这里要特别说一个坑Tomcat 7 官方文档写着最低支持 Java 6但到了 JDK 9 之后Java 模块化把javax.annotation这些包移出了默认加载列表直接拿 JDK 9 以上跑 Tomcat 7经常启动到一半就抛ClassNotFoundException。强行处理的话要在 JVM 参数里加--add-modules折腾一圈不如老老实实用 JDK 8。Maven 方面没什么玄学老项目一般把maven.compiler.source和target配成 1.8打出来的 war 包放进 Tomcat 7 就能跑。如果老板让你“支持 Java 21”那答案也很明确升级到 Tomcat 10.1 或 11顺带把代码里的javax.*换成jakarta.*工程量是逃不掉的。2. 环境准备与安装配置解压之后这五步做完就能跑2.1 解压后先认识目录结构把tomcat-7.0.108.zip解压到一个没有中文、没有空格的路径比如D:\apache-tomcat-7.0.108。解压完不要急着双击 startup先把目录认清楚后面排错全靠这几个文件夹。目录作用使用要点bin启动、关闭脚本所在startup.bat、shutdown.bat、catalina.bat 都在这conf核心配置文件server.xml、web.xml、tomcat-users.xmllib公共运行库不要随便往这里塞自己的 jarlogs日志目录排错第一站temp临时文件目录可清空webappsWeb 应用部署目录默认应用、war 包都放这workJSP 编译后的 class 和临时文件出诡异问题时可清空重建其中有三个目录我要单独提醒。webapps是你部署 war 包的地方Tomcat 启动时会自动扫描并解压work是 JSP 第一次访问时编译产物的缓存目录很多“改了页面不生效”的怪问题删掉work里的对应目录重启就好logs里的catalina.outLinux或catalina.日期.logWindows是排查启动失败的首选档案。2.2 JAVA_HOME 和 CATALINA_HOME 的配置细节Tomcat 本身是 Java 程序启动脚本会去找JAVA_HOME或JRE_HOME。如果找不到Windows 下就是启动窗口一闪而过Linux 下直接报Neither the JAVA_HOME nor the JRE_HOME environment variable is defined。我建议把JAVA_HOME指到 JDK 主目录注意不是 bin 目录也不是jre目录。比如JAVA_HOMED:\Java\jdk1.8.0_202 CATALINA_HOMED:\apache-tomcat-7.0.108 PATH%JAVA_HOME%\bin;%CATALINA_HOME%\binLinux 环境则是在/etc/profile或~/.bashrc里加export JAVA_HOME/usr/local/jdk1.8.0_202 export CATALINA_HOME/opt/apache-tomcat-7.0.108 export PATH$JAVA_HOME/bin:$CATALINA_HOME/bin:$PATHCATALINA_HOME不是强制要求但建议配置。很多脚本和工具会读取它来定位 Tomcat 目录配好之后避免后续在各种工具里反复选路径。配置完打开新终端输入java -version和echo %CATALINA_HOME%或echo $CATALINA_HOME验证一下比直接启动 Tomcat 更能确认环境变量有没有生效。2.3 第一次启动用前台模式别用 startup新手最容易犯的错是双击startup.bat看到一个黑窗口一闪而过就慌了。我自己的习惯是第一次启动一定用前台模式Windows 下运行catalina.bat runLinux 下运行catalina.sh run。这样 Tomcat 启动日志会直接打在当前终端报错信息一屏看得清清楚楚不存在“闪退找不到原因”的问题。看到类似下面的输出就说明启动成功了信息: Server startup in [4321] milliseconds然后用浏览器访问http://localhost:8080能看到 Tomcat 默认首页。如果页面打不开先检查 8080 端口是不是被占了再回头去看控制台日志。确认成功后后续日常使用再切回startup.bat或startup.sh后台启动。Tomcat 7 的默认配置里HTTP 端口是 8080关闭端口是 8005。这两个端口都写在conf/server.xml里如果环境里有冲突改掉后重启即可。3. IDEA 里跑 Tomcat 的两种主流路子3.1 企业版Run Configuration 加 Tomcat ServerIDEA 企业版对 Tomcat 支持得很好。打开Run/Debug Configurations点左上角找到Tomcat Server - Local然后在Application server区域点Configure选中解压出来的 Tomcat 主目录即可。重点是 Deployment 配置。点击Deployment标签页选Artifact如果是 Web 项目一般会出现两兄弟xxx:war和xxx:war exploded。我强烈建议调试阶段选war exploded它把项目按目录结构展开部署前端页面修改后刷新就能生效而完整的 war 包每次修改都要重新打包开发效率差距很大。然后设置Application context比如填/classic-web那访问路径就是http://localhost:8080/classic-web。最后启动IDEA 会自动拉起 Tomcat控制台切走等 “Server startup” 出来就能调试了。3.2 社区版用 Smart Tomcat 插件曲线救国IDEA 社区版免费但没集成 Tomcat Server 功能。解决办法是装一个名为Smart Tomcat的插件在插件市场搜一下就能找到。装完重启 IDE在Run/Debug Configurations里会出现一个Smart Tomcat配置项。配置也很简单Tomcat Server path选 Tomcat 解压目录Context Path填项目上下文路径Deployment选择war exploded或者直接选项目构建后的输出目录。它本质上是用 java 命令手动把catalina.classpath和你的项目输出目录拼起来启动省去了社区版没有 Web 模块的麻烦。实际用下来Smart Tomcat 应付日常 CRUD 项目的调试完全够用。它的主要短板是没有完整的管理界面和 Deployment 热替换机制改完 Java 代码后需要手动重启才能看到效果但配合 IDEA 自带的 Build 和 Debug调试逻辑已经足够顺手。3.3 war 包部署路径与常见误区从 IDEA 或 Maven 打包出来的 war 包部署路径并不是什么神秘位置扔到webapps目录下重启或等 Tomcat 自动解压就行。Tomcat 7 默认开启了autoDeploy它会检测 war 包变化并自动展开。一个经常出现的误区是改完代码重新打了 war 包覆盖到webapps下结果访问还是旧页面。这种情况十有八九是work目录里的旧编译缓存还在停掉 Tomcat删除work目录下的对应项目文件夹再重启就好。另外war 包正确部署后logs下会生成类似localhost.2024-01-01.log的日志文件里面记录了部署时报的异常比浏览器里看到的 404 有用得多。如果你不想把项目塞进webapps也可以在conf/server.xml的 Host 节点下配一个 Context用docBase指向外部的项目目录。但这种做法我建议只在开发联调时用生产环境还是标准化 war 包维护成本最低。这里还顺带提一句如果你用的是 Spring Boot 项目比如常见的“诺依”框架外部 Tomcat 和内嵌 Tomcat 会是两个容易互相干扰的存在。Spring Boot 默认内嵌 Tomcat 并占用 8080如果同时开了外部 Tomcat 也监听 8080启动必然报端口冲突。要打 war 包丢到外部 Tomcat 跑需要在pom.xml里把spring-boot-starter-web的tomcat依赖排除掉同时让启动类继承SpringBootServletInitializer并重写configure方法。这两步做完外部 Tomcat 才能正常接管请求。4. 启动慢、APR、线程池与 JVM 参数把默认配置调顺手4.1 启动慢的最常见原因Tomcat 启动慢是个老话题。如果你在 Linux 上启动一个简单的空 Tomcat 都要几十秒甚至几分钟第一个要怀疑的就是SecureRandom问题。JDK 在 Linux 上默认从/dev/random读取随机数而/dev/random在没有足够系统熵时会阻塞等待导致 Tomcat 卡在 SessionID 生成上。解决办法是在启动脚本里加上 JVM 参数让 JDK 从/dev/urandom读取随机数。在catalina.sh或catalina.bat顶部附近添加JAVA_OPTS$JAVA_OPTS -Djava.security.egdfile:/dev/./urandom注意这里写的是file:/dev/./urandom中间有个多余的./看着别扭但这是网上流传广泛且实测有效的写法能绕过某些 Java 版本的 bug不要自作主张改成干净的路径。另一个启动慢根源是 Jar 扫描。Tomcat 7 的JarScanner会扫描 webapp 下所有依赖 jar 去查找META-INF/web-fragment.xml和 TLD 文件依赖多了启动自然慢。如果只是内部老系统可以在conf/catalina.properties的org.apache.catalina.startup.ContextConfig.jarsToSkip列表里把无注解的通用 jar 加进去减少扫描范围。不过这个配置改起来要小心不认识的 jar 先别乱加否则 JSP 标签库可能失效。4.2 APR 那个红色提示是错误吗启动 Tomcat 时看到一行红色英文字母写着The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path。不少第一次见的人以为 Tomcat 坏了跑过来问“启动失败”。它不是错误只是一个提升性能的建议。APR 是 Tomcat Native 库利用操作系统层面的特性优化 IO 和内存使用。没有它Tomcat 走的是 JVM 自带的 NIO/BIO 通路完全不影响正常运行。如果只是开发调试看到这行字忽略即可。如果确实要装Windows 平台需要下载tcnative-1.dll放到PATH能找到的目录Linux 需要安装libtcnative相关的系统包装完后重启就能看到Loaded APR based Apache Tomcat Native library之类的提示。说实话在 7.x 版本上APR 主要对静态文件传输和 SSL 有一定提升老项目用不上就不必折腾。4.3 线程模型和线程池怎么调才有效Tomcat 7 默认的 HTTP Connector 用的是 BIO 模型也就是一个请求占一个线程线程粒度比较重。面对长连接或高并发场景这种模型很快会把线程池打满。如果你要优化可以在conf/server.xml的 Connector 上把 protocol 改成 NIOConnector port8080 protocolorg.apache.coyote.http11.Http11NioProtocol maxThreads400 minSpareThreads40 acceptCount200 connectionTimeout20000 redirectPort8443 /NIO 模型下一个选择器线程可以同时监控大量连接线程不再和请求一一对应。说回热词里那个“Tomcat 里一个线程对应 Linux 线程”的问题在 HotSpot JVM 里Java 线程和操作系统内核线程基本是一对一映射的每个 Java 线程最终会对应一个内核级线程但 Tomcat 的请求处理线程池和 NIO 选择器线程不是同一个概念BIO 模式下一个连接占一个 Tomcat 工作线程NIO 模式下连接被 Selector 管理工作线程只是在数据就绪时才被分配过去。线程池参数也别盲目调大。maxThreads默认 200对绝大多数内部系统都够用。调得太大线程上下文切换开销反而拖垮性能而且线程池大小要和应用后端的数据库连接池、下游接口耗时一起估算比如每个请求阻塞在数据库 200ms那你线程开 500 个数据库连接池只有 50等着排队的效果和 200 个线程基本没差。更精细的做法是定义独立的 ExecutorExecutor namemyExec namePrefixcatalina-exec- maxThreads300 minSpareThreads30 maxQueueSize200/ Connector port8080 protocolorg.apache.coyote.http11.Http11NioProtocol executormyExec ... /这种方式把线程池从 Connector 里解耦出来多个 Connector比如 HTTP 和 HTTPS可以共用同一个池。5. 折腾中遇到的问题排查实录5.1 启动闪退与端口占用Tomcat 启动闪退九成以上是环境变量配置问题。Windows 双击startup.bat后窗口一闪就没先打开命令行手动执行catalina.bat run这样错误信息会留在终端里。最常见的是JAVA_HOME没配好或者配到了 JRE 目录而不是 JDK 目录。端口占用是第二大类。启动时报Address already in use: JVM_Bind那就是端口被别的进程占了。Windows 下用命令行查netstat -ano | findstr 8080 taskkill /F /PID 进程号Linux 下用ss -lntp | grep 8080 kill -9 进程号需要注意别只查 HTTP 端口 8080Tomcat 的关闭端口 8005 也可能冲突。有时候防火墙或 Docker 转发规则会把 8005 悄悄占掉启动日志里能看到Server.close相关异常。两个端口一起确认省得反复启动失败找不到原因。5.2 RMI TCP Connection 线程是从哪来的有人用 jstack 或 jconsole 查看 Tomcat 进程时会发现不少名为RMI TCP Connection的线程以为是什么恶意连接。这些线程不是 Tomcat 处理 HTTP 请求的工作线程而是 JVM 自带的 JMX/RMI 通信线程。来源主要有两个。一个是 JVM 参数里开了 JMX 远程管理比如启动脚本里有-Dcom.sun.management.jmxremote之类的配置JVM 会启动 RMI 注册服务和 TCP 连接监听线程。另一个是 IDE 调试 Tomcat 时IDEA 会自动往 JVM 里注入 JMX 参数来获取进程状态所以你自己没配过也会有这些线程。排查方法很简单看启动日志和启动命令。如果是在 IDEA 里跑的那基本是 IDE 加的参数如果是独立服务器上出现查一下catalina.sh或环境变量里的JAVA_OPTS有没有相关配置。不需要刻意去杀这些线程正确做法是去掉不需要的 JMX 配置然后重启。5.3 优雅关闭与强制关闭正常情况下关闭 Tomcat 用shutdown.sh或shutdown.bat。它会向关闭端口默认 8005发送一条SHUTDOWN命令让 Tomcat 走完清理流程再退出。但实际运维中经常遇到关闭脚本执行后半天不退出那是因为 Web 应用里还有非守护线程活着Tomcat 在等待线程池回收。这时候只能强制结束Linux 可以先kill对应 SIGTERM给它几秒时间再不行就kill -9。快捷一点的命令pkill -9 -f catalina这会按命令行匹配杀掉所有 Tomcat 相关进程切记在服务器上执行前先确认匹配范围。Windows 下taskkill /F /IM java.exe会把所有 Java 进程一起干掉如果机器上跑了别的 Java 服务慎用。从稳妥角度讲shutdown.sh后等 10 秒再检查进程是否还在最后才上kill -9这个顺序才是完整的“优雅关闭”。5.4 高频问题速查表问题现象可能原因推荐处理访问项目 404上下文路径写错或 war 未解压确认Application context与webapps目录结构控制台中文乱码Windows 控制台编码不匹配conf/logging.properties里ConsoleHandler.encoding改为 GBKURL 传参中文乱码GET 请求编码问题server.xml的 Connector 添加URIEncodingUTF-8改了 JSP 不生效work 缓存旧编译产物删除work对应目录后重启想用 Java 21 跑 Tomcat 7版本不支持升级 Tomcat 10.1并迁移到jakarta.*需要 WebDAV 功能默认未启用在web.xml开启WebdavServlet设readOnlyfalse仅限内网Apache 与 Tomcat 集成需要 AJP 或反向代理走mod_proxy_ajp指向 Tomcat 的 8009 AJP 端口远程用 Jacoco 统计覆盖率未启动 agent在catalina.sh的JAVA_OPTS里加-javaagent:/path/jacocoagent.jardestfile...重启后生成 exec 文件还有一点要单独说conf/web.xml是全局部署描述符它会被所有 web 应用继承conf/server.xml、conf/context.xml同理。改这三个文件之前先备份。我见过有人在全局web.xml里加了自定义过滤器直接导致所有应用启动异常。能用应用自身WEB-INF/web.xml解决的就别去动全局配置。最后再说两句接手老项目时最忌讳“手痒升级”。Tomcat 7.0.108 配 JDK 8 是很多系统验证过的稳定组合只要你不用它暴露公网、不追求 HTTP/2 这类新特性它就能一直安静地跑下去。平时排查问题时也多看logs目录和work目录这两个地方能解释绝大多数“诡异现象”。如果后续真要迁移我的建议是先在测试环境用同一份 war 包分别跑 Tomcat 9 和 10.1观察依赖兼容性再决定改造成本。老系统最怕的从来不是版本旧而是没有任何预案的原地升级。先跑通、再调优永远比先调优、再跑通靠谱。本文还有配套的精品资源点击获取