ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Windows 64位 Tomcat 8.5.38 免安装部署与避坑指南

Windows 64位 Tomcat 8.5.38 免安装部署与避坑指南

简介:Apache Tomcat 8.5.38 Windows x64 版是一款面向 Java Web 开发者、J2EE 初学者以及需要本地调试 Servlet/JSP 应用人员的轻量级 Web 容器,可用于搭建开发测试环境、部署 war 应用并理解 Tomcat 的目录组织与运行机制。压缩包共 645 个文件,约 11.08MB,涵盖 html 文档、class 字节码、java 源码、jsp 页面、jar 依赖库、xml 配置、bat/sh 脚本及图片字体等类型,覆盖 bin、conf、lib、webapps 等典型目录,解压后即可按标准结构启动,也便于核对发行包的文件完整性与各模块用途。已有 140 人学习下载,适合希望动手验证 Servlet/JSP 容器行为、排查部署问题的读者参考。内容涉及 server.xml、web.xml、tomcat-users.xml 等核心配置,也包含 Manager 与 Host Manager 管理入口,读者可据此熟悉应用部署、用户权限设置、日志查看、连接器调整及基础性能调优思路,对目录结构、配置项与实际运行的对应关系形成更直观的认识,并为课程设计、小型项目上线前测试提供可直接使用的容器基础。

1. 从一次双击闪退说起

手上一个跑了些年的 J2EE 老项目要换机器,war 包往 apache-tomcat-8.5.38-windows-x64.zip 解出来的目录里一丢,双击 startup.bat,黑窗口刷两行就没了;换个端口重启,浏览器又甩回来一个 400 Bad Request。这套 Windows 64 位的 tomcat 8.5.38 免安装包看着是解压即用,真正卡人的从来不是解压本身,而是 JDK 版本、CATALINA_HOME 指向和 server.xml 里那几行没人愿意细看的默认值。它适合还在维护 javax.servlet 3.1 那套 J2EE Web 项目、需要在 Windows 机器上快速起一个容器的场景;要是新项目直接上 Jakarta 命名空间,这个版本就别考虑了。下面按我实际装机的顺序走一遍。

2. 装前环境盘点:JDK 版本和落地目录先定死

装 Tomcat 翻车,十次里有六次不是 Tomcat 的问题,是 JDK 选错或者路径里带了个空格。这一章不动手,只做三件事:把 JDK 版本定下来、把目录规划好、把机器状态确认一遍。做完再解压,后面能省掉一半回头路。

2.1 8.5.38 到底该配哪个 JDK

Tomcat 8.5 这一支官方要求是 Java 7 及以上,8.5.38 是这个分支里偏后期的一个小版本,规范上实现的是 Servlet 3.1、JSP 2.3、EL 3.0、WebSocket 1.1,也就是 J2EE 7 那一套。版本能跑和跑得舒服是两回事,我给个我自己的取舍表:

JDK 版本能不能跑我的实际取舍
JDK 7能,官方最低要求不推荐,TLS 和加密套件都偏老,连内网走 HTTPS 都别扭
JDK 8能,最匹配首选,8.5.38 时代的默认搭档,JSP 编译、连接池、日志都最省心
JDK 11能启动,能部署可以跑,但反射类库和部分 JSP 标签库会冒模块访问告警,要逐个加 --add-opens
JDK 17 及以上不建议Jasper 编译和老 jar 的反射容易出问题,救起来性价比极低

选 JDK 8 还有个现实原因:很多老项目的 pom 里写死了javax.servlet-api:3.1.0,JDK 8 加 Tomcat 8.5.38 是这套组合里最没有惊喜的搭配。JDK 9 之后模块化带来的访问限制,对老依赖是纯粹的负担,加参数能压住,但没必要给自己找事。

先把 JDK 装到不含空格和中文的路径,比如C:\env\jdk1.8.0_202,然后临时在命令行里验证一遍,别急着写进系统环境变量:

:: 只在当前 cmd 窗口生效,用来确认版本和路径对不对 set "JAVA_HOME=C:\env\jdk1.8.0_202" set "CATALINA_HOME=C:\env\apache-tomcat-8.5.38" set "PATH=%JAVA_HOME%\bin;%PATH%" java -version echo %JAVA_HOME%

java -version要能看到 1.8.0_xxx 这一行,并且输出来自你刚设的目录,而不是机器上原来那个 JDK。这一步的意义在于隔离:很多机器上装了不止一个 JDK,PATH里排在前面的那个往往是别的工具带进来的,Tomcat 启动时用的是JAVA_HOME,但你在命令行敲java用的是PATH,两者不一致时排查会非常痛苦。我一般让两者指向同一个目录,之后所有验证命令才有意义。

提示:Tomcat 的启动脚本优先认JAVA_HOME,没有才去找JRE_HOME。只装了 JRE 的机器必须设JRE_HOME,两个都不设,startup.bat 会直接退出,而且窗口一闪而过不给你看原因。

2.2 目录规划:空格、中文、括号都是雷

C:\Program Files\下面放 Tomcat 是最常见的坏习惯。启动脚本本身能扛住带空格的路径,但service.bat注册 Windows 服务时对路径的引号处理历史上一直有缝,路径里再带个中文或者括号,失败概率直线上升,而且报错信息经常只有一句没头没尾的提示。

我的固定做法是统一放在一个扁平目录下,JDK 和 Tomcat 平级:

C:\env\ ├── jdk1.8.0_202\ └── apache-tomcat-8.5.38\ ├── bin\ ├── conf\ ├── lib\ ├── logs\ ├── temp\ ├── webapps\ └── work\

这样规划还有一个好处:将来要在同一台机器上跑第二个实例,直接把目录复制一份改端口就行,不用去动任何全局配置。Tomcat 支持CATALINA_BASE概念,一个CATALINA_HOME可以对应多个CATALINA_BASE,每个 base 有自己的 conf、logs、webapps、work。字段说明如下:

  • CATALINA_HOME:程序本体所在目录,放 bin 和 lib,一般不变。
  • CATALINA_BASE:运行实例目录,放 conf、logs、webapps、work,有几个实例就有几个。
  • 单实例部署时两个可以指向同一个目录,一旦要拆,只改CATALINA_BASE就行。

如果不设CATALINA_BASE,Tomcat 启动时会默认用CATALINA_HOME作为 base,这是大多数人的默认状态。理解了这个分层,后面「改了配置为什么不生效」这类问题就有了排查方向。

2.3 装前清单:三条命令确认这台机器能不能开工

解压之前先跑三条命令,能挡掉一半的返工。

:: 1. 确认 JDK 版本和来源 java -version :: 2. 确认 JAVA_HOME 有没有被别的东西污染 echo %JAVA_HOME% :: 3. 确认 8080 和 8005 没被占用 netstat -ano | findstr ":8080 :8005"

对照表如下:

检查项期望结果不符合怎么办
JDK 版本1.8.0_xxx装 JDK 8,路径避开空格
JAVA_HOME指向刚装的 JDK,不带引号和分号清掉旧值重设,改完必须重开 cmd
8080 / 8005没有输出,或者输出的是你要停的进程换端口,或按 PID 停掉占用进程

netstat -ano输出了行,就带上最后的 PID 去tasklist | findstr <PID>看是谁。这里有个血泪经验:环境变量改完不重开命令行窗口,读到的永远是旧值,echo %JAVA_HOME%看着对,实际 Tomcat 拿到的可能还是系统里那份旧的。改完全局变量,关掉所有 cmd 窗口重新开一个,这是铁律。

3. 解压落地:从 zip 到能开机自启的服务

免安装包的好处是没有注册表污染,坏处是所有「安装」动作都得你自己补上:目录校验、启动参数、服务注册。这一章把这三件事做完。

3.1 解压后先核对目录结构

用系统自带解压不一定会出问题,但遇到压缩包损坏时的提示很含糊,我一般用 7-Zip 之类的工具解压到C:\env\,然后把解压出来的目录重命名成apache-tomcat-8.5.38,去掉版本后面可能带的额外后缀,保证路径干净。

解压完别急着启动,先确认核心文件在不在:

路径作用缺失表现
bin\startup.bat/catalina.bat启动脚本双击无反应,文件根本不存在
bin\service.bat注册 Windows 服务想做成服务时抓瞎
conf\server.xml端口、Host、Context 都在这里启动报错或用了默认端口
lib\catalina.jar容器主体启动立刻抛 ClassNotFoundException
webapps\ROOT默认首页访问 8080 是 404

webapps下面默认还有docs、examples、host-manager、manager几个目录。examples在生产环境应该删掉,但在装完验证阶段它是很好用的试金石,先留着,等第 6 章验证完再决定去留。

3.2 第一次启动用 catalina.bat run,不要用 startup.bat

startup.bat 是后台式启动,起一个子窗口就退出,报错信息在你的眼前一闪而过就没了。第一次启动我强烈建议用前台方式:

:: 进到 bin 目录,-d 保证盘符也切过去 cd /d C:\env\apache-tomcat-8.5.38\bin :: run 表示前台运行,报错直接打在窗口里 catalina.bat run

run和start的区别就在这:start会新开一个窗口跑,父窗口立刻返回,你看到的是父窗口的退出码;run当前窗口直接阻塞,任何异常堆栈都留在屏幕上。启动成功的标志是倒数几行出现Server startup in xxxx ms,这个数字是毫秒,没有这个数字就是没起来。

启动过程会输出大量 JULI 日志,其中有一条带org.apache.catalina.core.AprLifecycleListener的 INFO,提示 APR 本地库没找到,这条是正常现象,Windows 免安装包默认不带 tcnative,不影响 HTTP 服务,不用管它。

日志文件在logs\下,按日期滚动:catalina.YYYY-MM-DD.log是主日志,localhost.YYYY-MM-DD.log是应用级日志。Windows 下没有 Linux 里那个catalina.out,别去找。

3.3 用 setenv.bat 摆 JVM 参数,别改 catalina.bat

要加内存、改编码、设时区,正确位置是bin\setenv.bat。这个文件默认不存在,需要你自己建,Tomcat 启动时会自动去读它,读完再拼参数。

:: 文件位置:C:\env\apache-tomcat-8.5.38\bin\setenv.bat :: 显式指定 JDK,避免机器上多版本打架 set "JAVA_HOME=C:\env\jdk1.8.0_202" :: CATALINA_OPTS 只在启动时生效,shutdown 时不带 set "CATALINA_OPTS=-Xms512m -Xmx1024m -Dfile.encoding=UTF-8 -Duser.timezone=GMT+08" :: 需要额外开放模块时才用,JDK 8 上通常不需要 rem set "JAVA_OPTS=%JAVA_OPTS% --add-opens java.base/java.lang=ALL-UNNAMED"

参数逐个说清楚:

  • -Xms512m:初始堆,设小了启动后要频繁扩容,设大了占机器内存。512m 起步对小项目够用。
  • -Xmx1024m:最大堆,Xms和Xmx设成一样能避免运行期扩容抖动,但 Windows 上会立刻占用物理内存,按机器实际情况调。
  • -Dfile.encoding=UTF-8:影响 JVM 默认字符集,读配置文件、写日志都吃这个参数。
  • -Duser.timezone=GMT+08:容器里的时间跟本地对齐,避免日志时间戳错 8 小时。
  • CATALINA_OPTS和JAVA_OPTS的差别:后者在停止实例时也会被带上,如果你在里面写了堆参数,执行 shutdown 时会真的去申请一大块内存,机器紧张时可能卡住。启动参数放CATALINA_OPTS是更稳的选择。

setenv.bat里必须用set "VAR=value"这种带引号的写法,等号两边别加空格,否则变量值会带上一串尾随空格,表现为路径明明对却找不到文件。

3.4 注册成 Windows 服务,以及怎么卸干净

要开机自启就得做成服务,脚本是bin\service.bat,前提是CATALINA_HOME已经设好,并且路径不含空格。

cd /d C:\env\apache-tomcat-8.5.38\bin :: 安装服务,第一个参数是服务名,建议带版本号便于机器上并存多个实例 service.bat install Tomcat8538 :: 卸载,先停服务再 remove net stop Tomcat8538 service.bat remove Tomcat8538

service.bat install不带参数时默认服务名是Tomcat8,机器上装过别的 Tomcat 就会撞名,装之前先sc query Tomcat8看一眼。安装完服务默认是手动启动,需要开机自启就去服务管理器里改成自动。

服务方式运行和命令行方式运行有一个关键差异:服务启动时工作目录和环境变量来自系统服务和注册表,不再继承你当前 cmd 窗口的临时变量。所以你在窗口里set CATALINA_HOME=...然后装服务,命令行的临时设置其实已经进去了,但之后改setenv.bat才是长期有效的做法。卸载时如果服务还在运行,remove会失败并提示服务正在使用,必须先把服务停掉。卸载完别以为就干净了,work和temp下还留着编译产物和临时文件,换版本重装前把它们清空,能避免很多「明明换了包行为没变」的诡异现象。

4. server.xml 配置:端口、Host、部署方式三处必改项

conf\server.xml是整套配置的核心,装完不改,早晚出问题。这一章改三处:连接器、Host,以及部署方式。

4.1 Connector:端口和编码

默认的 Connector 长这样,注释掉的是 AJP:

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

我一般改成:

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" maxThreads="300" acceptCount="100" />
  • port:监听端口。8080 被占就换 8081、9090,改完两处都要动:这里和下一节说的redirectPort。顺便提一句,8005是 Server 的 shutdown 端口,8009是 AJP,Windows 上如果没跑 Apache 前端,AJP 那个 Connector 直接整段注释掉,少一个暴露面。
  • protocol="HTTP/1.1":在 Tomcat 8.5 里这个写法会自动选 NIO 实现,不是老版本的 BIO。看到有人用org.apache.coyote.http11.Http11NioProtocol全类名,效果一样,写得啰嗦而已。
  • connectionTimeout:连接超时毫秒数,20000 是默认,长连接场景可以调大。
  • URIEncoding="UTF-8":Tomcat 8 起默认就是 UTF-8,这里显式写出来是为了防另一种情况——从 Tomcat 7 迁移过来的老server.xml里往往写着URIEncoding="ISO-8859-1",它会把默认值覆盖掉,然后 GET 请求里的中文参数全变问号。看到中文乱码先查这一行,别急着怪前端。
  • maxThreads/acceptCount:最大工作线程和等待队列。默认 200 和 100,内网小应用不用动;并发上来了先看线程池打满时的日志,再调这两个值,别一上来就调到 2000。

4.2 Host:用 IP 访问报 400 的真正原因

默认 Host 是:

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">

它的意思是只接受 Host 头为localhost的请求。你在服务器本机浏览器敲localhost:8080一切正常,同事在隔壁机器敲192.168.x.x:8080就返回 400 Bad Request 或者一个空白错误页,很多人第一反应是防火墙,其实防火墙压根没参与,是 Host 匹配不上。

改法有两种,我倾向加 Alias,不破坏默认行为:

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Alias>192.168.1.20</Alias> <Alias>app.internal</Alias> </Host>
  • name:主主机名,保持localhost。
  • Alias:额外接受的域名或 IP,可以写多个,内网用 IP 的直接加 IP,配了 hosts 或内网 DNS 的加域名。
  • appBase:应用根目录,相对路径是相对于CATALINA_BASE。
  • unpackWARs:war 是否解压运行。设false时直接从 war 里读,启动快但静态资源读取效率低一些,我一般保持true。
  • autoDeploy:是否自动部署新丢进来的 war。开发机开着方便,生产环境我通常关掉,改由 manager 或重启控制发布节奏。

如果直接把name改成 IP,本机用localhost访问就会反过来匹配不上。所以加 Alias 更安全。

4.3 manager 与用户:conf/tomcat-users.xml

/manager/html是部署 war、看会话、点重启的图形面板,默认打不开,因为没配用户。文件是conf\tomcat-users.xml,默认内容几乎全是注释。

<tomcat-users xmlns="http://tomcat.apache.org/xml" version="1.0" encoding="UTF-8"> <role rolename="manager-gui"/> <role rolename="manager-script"/> <user username="ops" password="换成一串长口令" roles="manager-gui,manager-script"/> </tomcat-users>
  • manager-gui:浏览器访问/manager/html需要的角色。
  • manager-script:给 curl、Ant、CI 脚本调/manager/text/deploy用的角色,两个分开授权是刻意的设计。
  • password:别用默认示例里的短口令,这个面板权限等于应用部署权。

改完必须重启才生效。另一个高频坑是远程访问/manager/html返回 403:webapps\manager\META-INF\context.xml里有一条RemoteAddrValve,默认只放行127.0.0.1和::1。内网要放开,就得在这条 Valve 里加网段,收窄到具体机器比整段放开安全得多。

4.4 部署 war 的两种方式和 context 路径规则

第一种是丢包:把xxx.war放进webapps,autoDeploy="true"时几十秒内自动展开,访问路径就是 war 文件名去掉.war。demo.war对应/demo,ROOT.war对应根路径/。这里有个细节,war 名带版本号如demo-1.0.war,路径就是/demo-1.0,不会自动截断。

第二种是指定外部目录,war 不放进webapps,适合多实例共享同一份代码:

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="/demo" docBase="D:/apps/demo" reloadable="false" /> </Host>
  • path:访问前缀,写/demo就是/demo/xxx。
  • docBase:实际目录或 war 文件绝对路径,用正斜杠,别用反斜杠。
  • reloadable:改 class 是否自动重载。开发机设true省事,生产环境必须false,它会持续扫描类文件变更,白烧 CPU。

改了 Context 之后如果访问还是老行为,去work\Catalina\localhost\下把对应的编译产物删掉再重启。JSP 编译后的 class 缓存在那儿,有时候配置已经生效,跑的还是老代码。

5. 排查避坑:五个最常翻车的地方

这一章是我这几台机器上反复遇到的,按「现象 → 原因 → 解决」记,遇到对应症状直接查。

现象一:双击 startup.bat,黑窗口闪一下就没了。原因是启动脚本在进入 Java 之前就退出了,最常见的三种:JAVA_HOME没设、JAVA_HOME路径带了引号或尾随分号、JAVA_HOME指向的目录里没有bin\java.exe。窗口闪退看不到报错,是这件事最烦的地方。 解决:在 cmd 里cd /d到 bin 目录执行catalina.bat run,把报错捞出来;同时用echo %JAVA_HOME%确认值,注意输出里不能有引号。如果显示的是"C:\env\jdk1.8.0_202"或结尾多一个分号,重新设一遍,改完重开窗口。

现象二:本机能访问 localhost:8080,同事的机器访问不了,或者返回 400。原因分两层:400 是第 4 章说的 Host 匹配问题;完全连不上则是 Windows 防火墙没放行入站端口。 解决:先在本机用curl -I http://localhost:8080确认服务活着,再用netstat -ano | findstr :8080看监听地址是0.0.0.0:8080还是127.0.0.1:8080。如果只绑了回环地址,检查 Connector 上有没有写address="127.0.0.1"。都正常再去防火墙加 8080 入站规则,规则只对需要的网段开放。

现象三:改了 server.xml 的端口,重启后访问还是老端口。原因通常有三个:改的文件不是正在跑的那个实例的 conf(多实例下 CATALINA_BASE 指向别处);改完只是关掉了窗口,Java 进程还在,新端口被旧进程占着启动失败;或者服务方式运行,你重启的是命令行实例,服务那个根本没动。 解决:

:: 先看所有 java 进程和它们的 PID jps -l :: 找到跑着 catalina 的那个,确认它到底用的哪个目录 wmic process where "name='java.exe'" get ProcessId,CommandLine

看到命令行里的-Dcatalina.base=指向哪个目录,就知道该改哪个文件。改完用netstat -ano | findstr :新端口确认真的起来了。

现象四:控制台日志和日志文件里的中文全是乱码。原因是编码链路上有几处不一致:中文 Windows 的 cmd 默认是 GBK 代码页,而 Tomcat 8.5 的conf\logging.properties里java.util.logging.ConsoleHandler.encoding默认是 UTF-8,两边对不上。 解决:二选一。要么把 cmd 切到 UTF-8,chcp 65001再启动,缺点是这个窗口里其他中文输出可能变怪;要么把logging.properties里那个 encoding 改成 GBK。文件日志本身是 UTF-8 就没问题,用支持切编码的编辑器打开即可。两处别同时改,改一处看一处。

现象五:war 丢进 webapps 了,manager 里也能看到,访问就是 404 或者 503。原因一般是 context 路径不对、应用启动失败但容器没挂、或者 war 本身有依赖缺失。404 是路径没匹配上,503 是应用在但没起来。 解决:先看logs\localhost.YYYY-MM-DD.log,应用启动异常会记在这里,找SEVERE关键字。路径不对就检查 war 名有没有带版本号后缀;依赖缺失就看WEB-INF\lib下有没有对应的 jar,老项目常见的是 Servlet API 被一起打进 war 里,跟容器自带的冲突,排查时先把它排除掉。

注意:这五条里,凡是「改了没生效」的,九成先去确认进程到底读的哪个目录、哪个文件,别一上来就怀疑配置写错。进程和配置文件对不上,是所有玄学问题的源头。

6. 装完怎么验证跑通:三组自检和日志读法

装完能启动不等于装完能用。我固定走三组自检,从容器到 JSP 到面板,一层层往上验。

第一组,容器本身活着。命令和通过标准如下:

验证项命令通过标准
端口监听netstat -ano | findstr :8080出现0.0.0.0:8080的 LISTENING
HTTP 响应curl -I http://localhost:8080返回HTTP/1.1 200,Server 头带 Apache-Coyote
首页渲染浏览器打开http://localhost:8080出现 Tomcat 的默认欢迎页

第二组,JSP 和 Servlet 编译链路通。这一步最容易暴露 JDK 版本问题,因为 JSP 要经过 Jasper 编译成 class。别自己新建应用,直接访问自带的 examples:

:: examples 里的 servlet 示例,能出结果说明 servlet 容器正常 curl http://localhost:8080/examples/servlets/servlet/HelloWorldExample :: 随便挑一个 JSP 示例,能出页面说明 Jasper 编译正常 curl -I http://localhost:8080/examples/jsp/

第一个命令返回一段 HTML 说明 Servlet 链路通,第二个返回 200 说明 JSP 编译没被 JDK 版本卡住。如果这里报Unable to compile class for JSP,基本就是 JDK 版本过高或者JAVA_HOME指错了,回第 2 章重来。

第三组,管理面板和部署链路。浏览器开http://localhost:8080/manager/html,用第 4 章配的用户登录,能进去看到已部署应用列表就说明角色配对了。这一步验证的是部署通道,以后线上发版要么走这个面板,要么用manager-script角色配合脚本,通道通了才谈得上后续。

最后说一下日志怎么读。启动完成后,logs\catalina.YYYY-MM-DD.log里最后几行大概是这样:

信息: Starting ProtocolHandler ["http-nio-8080"] 信息: Server startup in 3287 ms

Server startup in这一行的毫秒数很有参考价值。冷启动三秒左右很正常,突然变成三十秒,通常是有应用在初始化时卡在外部连接上,比如数据库连接池首次建连超时,顺着这行往上看能定位到具体哪个应用拖慢了整体启动。排查线上问题也是同一个入口,findstr /C:"SEVERE"过滤一遍,比从头翻日志快得多。

从那以后,我每装一台 Tomcat,哪怕是解压即用的 zip 包,也强制走一遍「java -version+echo %JAVA_HOME%+netstat 看端口」这三条,再点启动。后来还发现一个小技巧,验证完把webapps\examples、docs和host-manager删掉,只留ROOT和manager,端口暴露面小一圈,也让下次启动快一点。这套流程走顺了,8.5.38 这个免安装包其实非常省心——难的是装之前那几步没做,而不是包装得不好。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表