技术演进中的开发沉思-136 java-servlet篇:环境
记得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 和应用,像 “把厨房和食材一起打包”,无论在哪个服务器上运行,环境都完全一致,解决了困扰我们多年的 “环境不一致” 问题。
四、常见陷阱:老程序员踩过的 “环境坑”
- JDK 版本不匹配陷阱:2005 年做 OA 系统时,我用 JDK 1.5 编译 Servlet,却部署到装了 JDK 1.4 的 Tomcat 上,结果报 “Unsupported major.minor version 50.0” 错误。后来才明白:JDK 版本就像 “衣服尺码”,编译时用的尺码(JDK 1.5)比运行时的尺码(JDK 1.4)大,自然穿不上。
- Tomcat 端口冲突陷阱:早年在 Windows 上开发,经常遇到 Tomcat 启动不了,查日志发现 “8080 端口被占用”。原来我同时开了迅雷,迅雷默认占用 8080 端口 —— 就像两个邻居抢同一个门牌号,谁也进不了家。解决办法是修改 Tomcat 的 conf/server.xml,把端口改成 8081:
<Connector port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
- 依赖包重复陷阱: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,工具在升级,但对 “写出可靠代码” 的追求从未改变。未完待续.........
更多推荐
所有评论(0)