如果你还在维护 2008 年前后上线的 Java Web 系统,那么 apache-tomcat-6.0.10 这个名字大概率会出现在你的日常工作里。这个版本的 Tomcat 当年是相当主流的 Servlet 容器,放到今天虽然已经不更新、不维护了,但很多老项目依然稳稳跑在它上面。这篇内容就是把 apache-tomcat-6.0.10 的完整使用步骤拆开讲:从 JDK 兼容性判断、环境变量配置,到启动脚本逻辑、war 包部署、虚拟目录映射,再到最常见的启动失败和乱码问题排查,全都会给出可以直接照抄的命令和配置。适合接手老旧项目的 Java 开发、运维,以及还在用 Tomcat 6 做二次开发的朋友参考。
1. 环境准备:JDK 匹配和目录结构
1.1 老项目为什么还在用 6.0.10
先说一个很多人会问的问题:Tomcat 都出到 10 了,为什么还要去啃 6.0.10?答案其实很现实:老系统的代码、中间件、数据库驱动很可能都是按 Tomcat 6 时代的规范写的,直接换高版本,轻则 NoSuchMethodError,重则整个容器都起不来。我接手过的一个内部管理系统,跑了十来年,业务逻辑里大量依赖 Tomcat 6 自带的 com.sun.el 和老的 JSP taglib 行为,往上迁移的工作量远比想象中大。所以对维护老项目的人来说,不是“想不想用 6.0.10”,而是“只能用 6.0.10”。
1.2 先确认 JDK 版本再动手
Tomcat 6.0.10 官方要求 Java 5 及以上版本,但实际生产里最稳的是 JDK 1.6。如果你机器上装的是 JDK 1.8 或更高,启动 Tomcat 时很容易碰到 UnsupportedClassVersionError,或者干脆任何网页都打不开。原因很简单:Tomcat 6 是在 Java 6 时代编译的,和 Java 8 里的类加载、安全管理器存在明显差异,强行运行就是给自己挖坑。
动手之前先看清楚当前 Java 版本,Windows 或 Linux 终端里执行:
java -version如果显示类似java version "1.8.x",建议先换回 JDK 1.6 或 JDK 1.7。Windows 下安装 JDK 后还要确认JAVA_HOME指向的路径里确实有 bin/java.exe,不要只改了环境变量却没实际安装对应版本。
注意:Tomcat 6.0.10 比较挑 JDK,别拿 JDK 8 去硬撑。如果你实在只能装 JDK 8,那更合理的方案是升级 Tomcat,而不是在这里折腾 6.0.10。
1.3 解压后的目录结构一次看明白
从官网下载apache-tomcat-6.0.10.zip或.tar.gz后,解压到任意不含中文和空格的路径下。Windows 上我习惯解压到D:\tomcat6,Linux 上建议/opt/tomcat6。解压后你会看到这些目录:
bin:存放启动、关闭脚本,包括startup.bat、shutdown.bat、catalina.bat、startup.sh等。conf:核心配置文件,最重要的就是server.xml和web.xml。lib:Tomcat 自身的类库,比如 servlet-api.jar、jsp-api.jar。logs:运行日志目录,启动日志和访问日志都在这。temp:容器运行时缓存临时文件。webapps:默认部署目录,war 包放这里就能被自动发布。work:JSP 编译后的 class 文件缓存目录,遇到 JSP 编译问题可以清空这个目录。common、server、shared:这三个目录是 Tomcat 6 特有的类库目录,分别放公共类、服务器内部类和共享类。老项目里偶尔需要把某些 jar 放到common/lib里才能被所有应用共享,这是 Tomcat 6 的典型套路。
2. 启动与停止:从环境变量到日志定位
2.1 必须配好的两个环境变量
启动 Tomcat 之前,先保证JAVA_HOME和CATALINA_HOME都设置正确。startup.bat脚本本身不会去找 Java,它依赖JAVA_HOME去定位 java 命令,也依赖CATALINA_HOME去定位 Tomcat 根目录。Windows 下可以在系统环境变量里添加:
JAVA_HOME=C:\Program Files\Java\jdk1.6.0_45 CATALINA_HOME=D:\tomcat6Linux 下可以在/etc/profile或当前用户的.bashrc里追加:
export JAVA_HOME=/usr/java/jdk1.6.0_45 export CATALINA_HOME=/opt/tomcat6 export PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin配置完记得source /etc/profile或重新打开终端。不少启动失败的案子,根源就是JAVA_HOME没配,导致执行 startup 时直接报Unable to find a javac compiler或JAVA_HOME is not defined correctly。
2.2 startup 脚本背后做了什么
Windows 下双击startup.bat,通常会看到黑窗口一闪而过,好像什么都没发生。这不是 Tomcat 没启动,而是启动脚本执行完就退出了。更稳妥的做法是先打开 cmd 命令行,手动切到 Tomcat 的 bin 目录,然后执行:
startup.bat这样控制台会实时输出启动日志,一旦启动报错,你能直接看到异常堆栈。你还可以用另一个更直观的前台启动方式:
catalina.bat runcatalina.bat run会强制 Tomcat 在前台运行,所有日志都直接打印在窗口里,排查启动问题比用 startup 舒服很多。Linux 上同理:
/opt/tomcat6/bin/startup.sh或者:
/opt/tomcat6/bin/catalina.sh run建议第一次启动或排错时都用catalina.sh run这种前台模式,看到Server startup in xxx ms才算真正启动成功。
2.3 验证启动状态和日志切入点
启动后浏览器访问http://localhost:8080/,看到 Tomcat 默认首页,说明启动成功。如果访问不了,第一件事不是重启,而是看日志。Tomcat 6 的日志默认输出到logs/catalina.out,Linux 下用:
tail -f /opt/tomcat6/logs/catalina.outWindows 下则直接看logs目录下的catalina.2025-xx-xx.log文件。正常情况下日志末尾会出现Server startup in 1789 ms,这句话是启动成功的标志。
停止服务用配套的 shutdown 脚本:
shutdown.bat/opt/tomcat6/bin/shutdown.sh千万不要图省事直接kill -9 PID,那样进程里的端口可能不会被立即释放,重启时就会碰到端口被占用的报错。
3. 部署 Web 应用:war 包、解压目录和虚拟目录
3.1 最快的部署方式:直接丢 war 包
如果你手里只有一个 war 包,那么部署动作简单到令人发指:把xxx.war复制到 Tomcat 的webapps目录下,然后启动或重启 Tomcat。Tomcat 6 默认开启了解压功能,启动后会自动把xxx.war解压成webapps/xxx目录。之后访问路径就是:
http://localhost:8080/xxx/注意这里的xxx是 war 包的文件名,不是包里的 context path。所以想控制访问路径,直接改 war 包文件名就可以。不过 war 包文件名尽量不要带中文、空格和特殊字符,Tomcat 6 对这些的处理能力很弱。
容易踩的坑:如果你是在 Tomcat 运行状态下覆盖原 war 包,容器不一定会自动重新解压。因为解压目录已经存在,Tomcat 会继续用旧的 class 文件,导致你辛辛苦苦改的代码完全不生效。
3.2 不想放 webapps?用 Context 映射虚拟目录
很多老项目的源码并不在 webapps 下,而是放在某个业务目录里,比如D:\projects\erp。这种情况下不需要复制文件,只需要配置一个 Context 指向实际目录。推荐的做法是新建一个独立的 xml 文件,放在conf\Catalina\localhost\目录下,文件名就是访问路径。比如要访问/erp,就创建conf\Catalina\localhost\erp.xml,内容如下:
<Context path="/erp" docBase="D:\projects\erp" reloadable="false" />修改后重启 Tomcat,访问http://localhost:8080/erp/就能直接映射到D:\projects\erp。这种独立 xml 配置比直接改server.xml更安全,因为不会影响全局配置,也方便单独移除某个应用。
如果你确实想直接在conf\server.xml里加,可以把<Context>节点写到<Host>内部,示例:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="/erp" docBase="D:\projects\erp" /> </Host>但我不建议长期用这种方式,每次修改server.xml后重启失败的风险偏高,而且一旦配置写错,整个容器都无法启动。
3.3 多应用共存与更新发布的正确操作
一个 Tomcat 上跑多个应用其实很简单,只要保证每个应用的访问路径不重复,war 包或 Context 路径不同即可。Tomcat 默认会为每个应用创建独立的类加载器,应用之间的依赖不会互相干扰,这也是老项目敢把多个系统放在同一个 Tomcat 里的原因。
更新应用时,最安全的操作顺序必须是:
- 停止 Tomcat,执行
shutdown.sh或shutdown.bat。 - 备份当前正在运行的应用目录(尤其是 webapps 下的解压目录和配置文件)。
- 删除旧的 war 包和解压目录,确保没留下旧 class 文件。
- 放入新的 war 包。
- 重新启动 Tomcat,观察日志确认无异常。
不要嫌麻烦跳过第 1 步。我见过太多人图省事,在服务运行状态下直接删除旧 war 包往里面塞新的,结果 Tomcat 在自动解压时锁住了文件,抛出一堆FileNotFoundException,应用卡死半天才恢复。老版本容器对热更新的支持没那么智能,老老实实重启才不会给自己添堵。
4. 启动失败与问题排查实录
4.1 启动脚本窗口一闪而过怎么办
闪退基本上可以锁定是环境变量问题,最常见的两类:
JAVA_HOME没有设置或设置错误。- Tomcat 解压路径中包含空格,导致脚本里的路径判断失效。
排查方法是先打开 cmd,手动执行 startup.bat,让报错信息留在窗口里。常见的报错包括:
The CATALINA_HOME environment variable is not defined correctly This environment variable is needed to run this program看到这个就去检查CATALINA_HOME到底有没有指向 Tomcat 根目录。还有一种情况是杀毒软件拦截了 java 进程,尤其 Windows 服务器上常见,报错信息五花八门,解决办法是把 Tomcat 的 bin 目录和 JDK 的 bin 目录加入杀毒软件白名单。
4.2 端口被占用:先查再改
启动时如果日志里出现:
java.net.BindException: Address already in use: JVM_Bind不用多想,肯定端口被占用。Tomcat 6 默认有三个端口:
| 端口 | 用途 |
|---|---|
| 8080 | HTTP 连接端口,浏览器访问入口 |
| 8005 | 接收 shutdown 指令的关闭端口 |
| 8009 | AJP 连接端口,一般用来和 Apache 配合 |
排查 8080 端口被谁占用,Windows 执行:
netstat -ano | findstr :8080会输出一行带 PID 的记录,然后通过tasklist | findstr PID查看进程名,再决定是杀掉这个进程,还是给 Tomcat 换个端口。修改端口在conf\server.xml里,找到如下节点:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />把port="8080"改成其他值,比如 8090。改完后访问地址跟着变成http://localhost:8090/。同时建议把 8005 和 8009 也一并改掉,出于安全考虑,老版本默认端口太容易被扫描到。
4.3 JDK 版本不兼容:UnsupportedClassVersionError 的真相
前面提到过 JDK 版本问题,这里展开说一下。如果你用 JDK 1.8 启动 Tomcat 6.0.10,表面上启动也许成功,但应用部署后访问时会报类似:
java.lang.UnsupportedClassVersionError: com/example/erp/LoginServlet : Unsupported major.minor version 52.0这个报错的意思是:你的 class 文件编译版本是 Java 8,而 Tomcat 6 运行在 Java 6 环境下,自然读不了。解决办法有两个方向:
- 把 JDK 换回 1.6,并确认 IDE 和项目的编译级别也改成 JDK 1.6。
- 或者干脆升级 Tomcat,别让老容器去兼容新字节码。
我处理过的案例里,还有一种是本地装了多个 JDK,JAVA_HOME指向了 JDK 6,但 PATH 里却先找到了 JDK 8 的 java.exe。此时脚本实际加载的 JVM 和JAVA_HOME不一致,就会出奇怪的问题。建议把 JDK 的 bin 目录明确放在 PATH 最前面,或者在 catalina.bat 里强制指定:
set JAVA_HOME=C:\Program Files\Java\jdk1.6.0_454.4 中文乱码:编码配置必须改
Tomcat 6 默认请求编码是 ISO-8859-1,不做任何处理的话,表单提交的中文到后端基本全乱。很多老项目里都有专门的过滤器去转码,但如果你从头搭环境,建议直接在server.xml的 Connector 上加上 URI 编码:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" />这样 GET 请求中的中文参数基本能解对。POST 请求的问题通常是后端读取 request 参数的编码不对,最常见的办法是在项目中配置 CharacterEncodingFilter,如果项目还在用 web.xml 而不是 Spring Boot,就加一段:
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>还有个容易忽略的点:JSP 页面本身要声明contentType="text/html; charset=UTF-8",否则即使容器编码对了,页面输出还是乱码。排查乱码时,按照“请求编码 -> 页面编码 -> 数据库连接编码”的顺序逐层检查,一般很快能找到问题点。
4.5 常见启动问题速查表
| 症状 | 可能原因 | 处理方式 |
|---|---|---|
| 双击 startup.bat 一闪而过 | JAVA_HOME 未配置或配置错误 | 用 cmd 运行,查看具体报错 |
| 浏览器无法访问 8080 | 端口被占用 | netstat 找到进程,杀进程或改端口 |
| 报 UnsupportedClassVersionError | JDK 版本过高或项目编译级别高 | 换 JDK 1.6,调整编译级别 |
| 部署后访问 404 | war 包名和路径不一致 | 确认访问路径为/war包名/ |
| 启动成功后很快自动停止 | shutdown 端口被其他程序占用,触发意外关闭 | 修改 8005 端口 |
5. 老版本的安全基线与运行调优
5.1 清理默认应用和默认页面
Tomcat 6 的 webapps 目录下默认带了 ROOT、docs、examples、manager、host-manager 这些应用。它们一方面会暴露 Tomcat 默认首页和示例代码,另一方面也可能成为攻击入口。部署生产环境时,建议先删除docs、examples、manager、host-manager,然后把 ROOT 目录里的内容也清空,保留空目录即可,这样访问根路径会返回 404,避免泄露容器信息。
删除后记得重启 Tomcat,让 webapps 目录重新加载。
5.2 修改 shutdown 端口和关闭指令
Tomcat 6 的server.xml底部有一段:
<Server port="8005" shutdown="SHUTDOWN">正常情况下,任何能访问 8005 端口的人发送SHUTDOWN字符串,Tomcat 就会直接关闭。默认端口和默认指令都是公开知识,危险系数很高。建议改成不常见的端口号和一个乱码一样的指令:
<Server port="8055" shutdown="mysecretword">只改端口还不够,还要保证 8005 这种管理端口不要暴露到公网,否则一样可以被远程探测。生产环境尽量用防火墙限制这个端口的来源 IP。
5.3 JVM 内存和连接数怎么调
老项目最烦的就是跑几个月后 OOM。Tomcat 6 运行在 Java 6 上时,除了堆内存,还有一个 PermGen 区很容易爆。默认配置下,只要应用加载的 class 文件多了,就报:
java.lang.OutOfMemoryError: PermGen space解决方案很简单,把 JVM 参数加上去。Windows 在catalina.bat文件开头附近加:
set CATALINA_OPTS=-Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256mLinux 在catalina.sh里加:
export CATALINA_OPTS="-Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=256m"Xms是初始堆大小,Xmx是最大堆大小,PermSize和MaxPermSize是永久区大小。具体数值根据机器实际内存和应用负载来调,但不要一下灌到 4G,因为 Tomcat 6 默认使用的连接器和垃圾回收器处理不了太大的堆。
连接数方面,Tomcat 6 默认的 HTTP 连接器模型性能一般,不建议盲目把maxThreads调得很大。可以在 Connector 上适当调整:
<Connector port="8080" protocol="HTTP/1.1" maxThreads="200" minSpareThreads="20" connectionTimeout="20000" redirectPort="8443" />maxThreads表示最大处理线程数,minSpareThreads是常驻空闲线程数。如果业务量不大,保持默认的 200 以内就够了。真正的问题是慢 SQL 和堵塞,多调线程数只能掩盖症状,不能解决问题。
5.4 日志切割和日常维护建议
Tomcat 6 的日志不像新版本那样按天自动切割得那么好,logs/catalina.out可能会变成几十 GB 的庞然大物,既占磁盘又影响排查效率。Linux 下建议通过logrotate做切割,配置可以这样写:
/opt/tomcat6/logs/catalina.out { daily rotate 15 compress missingok copytruncate }Windows 下没有现成的 logrotate,可以写个计划任务定期把日志文件复制走,然后清空原文件。注意清空日志前先确认当前 Tomcat 进程没有在写文件,否则可能出现文件句柄问题。
我个人在实际维护里的经验是,Tomcat 6.0.10 本身并不复杂,真正折磨人的反而是环境变量、JDK 兼容和端口冲突这些细节。遇到任何启动问题,先打开日志,从上往下看前几行,大部分原因都写在开头那里,比反复改 server.xml 高效得多。最后也提醒一下:如果你所在的团队还有选择权,尽量把老项目迁移到新版 Tomcat 或者嵌入式容器上,毕竟 6.0.10 已经太老太脆弱了,守住它只能算权宜之计。