记得2002 年我第一次搭建 Servlet 环境时,手里攥着 Sun 公司的官方文档,像捧着一本 “家电组装说明书”。那时还没有一键安装的 IDE,要让 Servlet 跑起来,得先搭好 “三座桥”:Java 开发环境(JDK)是 “地基”,Tomcat 是 “房子”,Web 应用(WAR 包)则是 “家具”—— 三者少一个,Servlet 都无法 “安家”。

Tomcat 本质是 Servlet 容器,就像小区的 “物业管理处”:它负责接收用户的 HTTP 请求(快递),找到对应的 Servlet(住户)处理,再把结果返回给用户。而 web.xml 或注解,相当于 “住户登记表”,告诉 Tomcat 哪个请求该找哪个 Servlet 处理。早年没有注解时,所有 “登记信息” 都要写在 web.xml 里,就像每次新增住户都要手动修改纸质登记表,繁琐又容易出错。

一、从 “手动敲命令” 到 “IDE 一键生成”

1. 手工创建 WAR 包

当年没有 Maven,打包全靠命令行,就像用手搓面团做馒头,步骤多还容易翻车:


# 1. 编译Servlet(需引入Tomcat的servlet-api.jar)

javac -cp D:\tomcat\lib\servlet-api.jar -d WEB-INF/classes src/OrderQueryServlet.java

# 2. 手动创建WEB-INF目录和web.xml

mkdir -p WEB-INF/classes WEB-INF/lib

# 3. 编写web.xml(相当于“住户登记表”)

cat > WEB-INF/web.xml << EOF

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4">

<servlet>

<servlet-name>OrderQuery</servlet-name>

<servlet-class>OrderQueryServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>OrderQuery</servlet-name>

<url-pattern>/queryOrder</url-pattern>

</servlet-mapping>

</web-app>

EOF

# 4. 打包成WAR包(jar命令手动压缩)

jar -cvf OrderWeb.war *

记得有次打包时漏了 WEB-INF 目录,WAR 包扔到 Tomcat 里根本识别不了,排查了两小时才发现是命令行敲错了路径 —— 现在想起来,那时候的开发更像 “手工匠人”,每一步都得亲力亲为。

2. IDE 自动化

现在用 IntelliJ IDEA 开发,打包就像用全自动面包机:只需配置好 Maven,点击 “Package” 按钮,IDE 会自动完成编译、依赖导入、WAR 包生成,甚至能直接部署到 Tomcat。关键配置在 pom.xml 里,相当于 “面包机食谱”:


<!-- Maven配置:自动引入Servlet依赖,生成WAR包 -->

<dependencies>

<!-- 无需手动复制servlet-api.jar,Maven自动下载 -->

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>javax.servlet-api</artifactId>

<version>4.0.1</version>

<scope>provided</scope> <!-- 告诉Maven:Tomcat已自带这个jar -->

</dependency>

</dependencies>

<build>

<finalName>OrderWeb</finalName> <!-- 生成的WAR包名 -->

<plugins>

<!-- 编译插件:指定JDK版本 -->

<plugin>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-compiler-plugin</artifactId>

<version>3.8.1</version>

<configuration>

<source>11</source>

<target>11</target>

</configuration>

</plugin>

</plugins>

</build>

二、实战场景:电商项目的环境抉择

2010 年我们做电商平台时,曾面临 “手工部署” 和 “IDE 部署” 的抉择:

  • 手工部署场景:生产环境用 Linux 服务器,我们把 WAR 包通过 FTP 上传到 Tomcat 的 webapps 目录,再执行sh shutdown.sh和sh startup.sh重启。这种方式像 “用扁担挑水”,稳定但效率低 —— 有次大促前紧急修复 bug,上传 WAR 包时网络断了,导致部署失败,差点影响开卖。
  • IDE 部署场景:开发环境用 IntelliJ IDEA,配置 Tomcat 后,点击 “Debug” 按钮就能实时部署。改完代码不用重启服务器,Ctrl+F9 就能热更新,就像 “用自来水龙头”,随用随取。但要注意:开发环境的热更新不能直接用在生产,否则可能出现 “内存泄漏”—— 就像家里的水龙头偶尔滴水没事,工厂的水龙头一直滴就会浪费大量水。

三、对比分析:四种环境搭建方式的 “优劣对决”

搭建方式

核心特点

像什么场景

电商 / OA 中的适配性

痛点

纯手动(命令行)

无依赖,全靠手动操作

用柴火灶做饭,步骤全手动

仅适合小型 Demo 项目

效率低,易出错

Eclipse+Tomcat

可视化配置,适合新手

用电饭煲做饭,按钮式操作

中小型 OA 系统

热部署不稳定,偶尔卡顿

IntelliJ IDEA+Maven

自动化程度高,支持热更新

用智能厨房,一键搞定

中大型电商项目

内存占用高,收费

Docker+Tomcat

容器化,环境一致性强

用外卖盒,打包好直接用

微服务架构的电商平台

学习成本高,需懂 Docker

印象最深的是 2018 年迁移电商项目到 Docker:之前开发环境和生产环境总是 “不一样”—— 开发时好的功能,到生产就报错,后来用 Docker 打包 Tomcat 和应用,像 “把厨房和食材一起打包”,无论在哪个服务器上运行,环境都完全一致,解决了困扰我们多年的 “环境不一致” 问题。

四、常见陷阱:老程序员踩过的 “环境坑”

  1. JDK 版本不匹配陷阱:2005 年做 OA 系统时,我用 JDK 1.5 编译 Servlet,却部署到装了 JDK 1.4 的 Tomcat 上,结果报 “Unsupported major.minor version 50.0” 错误。后来才明白:JDK 版本就像 “衣服尺码”,编译时用的尺码(JDK 1.5)比运行时的尺码(JDK 1.4)大,自然穿不上。
  1. Tomcat 端口冲突陷阱:早年在 Windows 上开发,经常遇到 Tomcat 启动不了,查日志发现 “8080 端口被占用”。原来我同时开了迅雷,迅雷默认占用 8080 端口 —— 就像两个邻居抢同一个门牌号,谁也进不了家。解决办法是修改 Tomcat 的 conf/server.xml,把端口改成 8081:
<Connector port="8081" protocol="HTTP/1.1"

connectionTimeout="20000"

redirectPort="8443" />

  1. 依赖包重复陷阱:2012 年做电商支付模块时,我在 WEB-INF/lib 里放了 servlet-api.jar,又在 Maven 里引入了这个依赖,结果 Tomcat 启动时报 “类重复” 错误。这就像 “买了两本一样的书”,放在同一个书架上,Tomcat 不知道该用哪本 —— 正确做法是在 Maven 里把依赖 scope 设为 provided,告诉 Maven“Tomcat 已经有这本书了,不用再带了”。

五、最佳实践:二十年环境搭建的 “经验总结”

Tomcat 深度配置

  • 生产环境修改 conf/tomcat-users.xml,添加管理员账号,方便通过 Web 界面管理应用:
<user username="admin" password="123456" roles="manager-gui,admin-gui"/>
  • 优化内存配置:在 bin/catalina.sh(Linux)或 bin/catalina.bat(Windows)里添加 JVM 参数,避免电商大促时内存不足:
# Linux:设置初始内存1G,最大内存2G

JAVA_OPTS="-Xms1024m -Xmx2048m -XX:+UseG1GC"

打包方式选择

  • 开发环境用 IDE 的热部署,节省调试时间;
  • 测试环境用 Maven 打包,通过 Jenkins 自动部署,减少人工操作;
  • 生产环境用 Docker 打包,确保环境一致性,支持快速扩容。

配置演进技巧

  • Servlet 3.0 以前用 web.xml 配置,适合老项目维护;
  • Servlet 3.0 及以后用注解,比如@WebServlet("/queryOrder"),就像 “给住户贴门牌号”,不用再改登记表(web.xml);
  • 混合配置时,注解优先级高于 web.xml,但尽量避免混合使用,否则容易 “找不到门牌号”。

调试环境配置

  • IDE 里配置 Tomcat 时,勾选 “Remote Debug”,就像 “给 Tomcat 装监控摄像头”,能实时看到代码运行状态;
  • 开发电商支付模块时,用 Postman 模拟 HTTP 请求,不用每次都启动前端页面,就像 “不用到餐厅就能点外卖”,提高调试效率;
  • 生产环境调试时,用日志代替断点,避免影响用户 —— 就像医院给病人看病,不能在手术时随便打断,只能通过检查报告(日志)分析问题。

六、现代价值:云原生时代的环境搭建

如今都是K8s时代了,但在 的 yaml 文件,里面依然有 Tomcat 的配置 —— 只是现在的 “房子”(Tomcat)被装在了 “集装箱”(Docker)里,由 K8s 负责 “运输” 和 “管理”。

云原生时代的环境搭建,本质是 “传统配置的升级”:

  • 自动化部署:用 Jenkins+K8s 实现 “代码提交后自动打包、部署”,就像 “工厂流水线”,不用再手动搬运;
  • 弹性伸缩:根据电商流量自动调整 Tomcat 实例数量,就像 “餐厅根据客人数量增减服务员”,不浪费资源;
  • 监控告警:用 Prometheus 监控 Tomcat 性能,就像 “给房子装烟雾报警器”,一旦出现问题(比如内存过高),立刻告警。

最后小结:

整理旧电脑时,翻出 2003 年的 Tomcat 安装包,大小只有 5MB,现在的 Tomcat 10 已经有 100 多 MB—— 但核心功能没变,依然是 Servlet 的 “家”。从手动敲命令到 IDE 自动化,从物理机到 Docker,环境搭建的工具在变,但 “让 Servlet 稳定运行” 的目标从未变过。就像我们老程序员,从用记事本写代码到用智能 IDE,工具在升级,但对 “写出可靠代码” 的追求从未改变。未完待续.........

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐