Java War包部署案例

wen java案例 1

一个Java War包在Tomcat集群中的完整部署实战

目录导读

  1. War包的本质与结构 – 为什么你的Spring Boot应用还需要War包?
  2. 部署前环境准备 – JDK版本、Tomcat参数、防火墙规则
  3. 五步核心部署流程 – 从上传War到平滑运行(附命令)
  4. 常见故障处理矩阵 – 内存溢出、端口占用、类冲突的急救方案
  5. 生产环境优化策略 – 开启APR连接器、JVM调优、监控指标
  6. QA:部署中最容易踩的6个坑 – 实战问答总结

War包的本质与结构

Java Web应用标准打包格式是WAR(Web Application Archive),很多人在开发时习惯用spring-boot-maven-plugin打成可执行Jar,但若需要部署到外部Tomcat、WebLogic或进行灰度分流时,传统War包反而更灵活。

Java War包部署案例

War包核心结构:

myapp.war
├── META-INF/          (清单文件、上下文配置)
├── WEB-INF/           (核心区,外部不可直接访问)
│   ├── classes/       (编译后的.class与资源文件)
│   ├── lib/           (项目依赖的第三方Jar)
│   └── web.xml        (Servlet映射、Filter/Listener注册)
└── static/ 或 asset/  (静态资源,如CSS/JS/图片)

关键区别: Spring Boot默认内嵌Tomcat,打成WAR后必须标记provided依赖,并排除内嵌容器,否则会引发ClassNotFoundException


部署前环境准备(决定成败的隐性因素)

1 JDK版本对齐

Tomcat 9.x/10.x必须匹配JDK 8+,检查命令:

java -version
/usr/local/tomcat/bin/version.sh

2 Tomcat参数调优(至少这三项)

编辑conf/server.xml中的<Connector>

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="500" minSpareThreads="50"
           connectionTimeout="20000" redirectPort="8443"
           maxPostSize="2097152" disableUploadTimeout="true" />

3 防火墙与反向代理

若使用Nginx,需放行8080端口,并配置:

proxy_pass http://tomcat-cluster;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

五步核心部署流程(真实生产命令)

步骤1:上传War包至指定目录

mkdir -p /opt/tomcat/webapps
scp local-app.war root@server:/opt/tomcat/webapps/

步骤2:处理同名冲突(关键!)

ls webapps/ | grep app
rm -rf app  app.war  # 先停Tomcat再删

步骤3:配置上下文根路径

修改conf/server.xml<Host>段,保证访问路径唯一:

<Context path="/myapp" docBase="myapp.war" reloadable="true" />

若想以根路径访问,则path=""

步骤4:启动并监控日志

/opt/tomcat/bin/startup.sh && tail -f /opt/tomcat/logs/catalina.out

启动成功的标志:

INFO: Deployment of web application archive [myapp.war] has finished

若出现Oracle.jdbc.driver.OracleDriver找不到,检查WEB-INF/lib是否存在驱动。

步骤5:验证多节点(可选)

在两台Tomcat上重复以上流程,用Nginx做负载均衡:

upstream backend {
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
}

常见故障处理矩阵(重点记忆)

现象 根本原因 应急命令/修改
OutOfMemoryError: Metaspace 类加载过多 set JAVA_OPTS=-XX:MaxMetaspaceSize=256m
Tomcat无法关闭 线程泄漏 kill -9 $(cat /opt/tomcat/temp/tomcat.pid)
Caused by: java.lang.IllegalArgumentException pom中打包漏了JSP mvn war:exploded 强制重新生成
访问404 上下文路径错误 conf/Catalina/localhost下添加同名XML
静态资源无法加载 Spring Security拦截 在Security配置中放行/static/**

生产环境优化策略

1 启用APR连接器(提升30%并发)

yum install tomcat-native -y
# server.xml改为 protocol="org.apache.coyote.http11.Http11AprProtocol"

2 JVM堆内存分级设置

export CATALINA_OPTS="-Xms2048m -Xmx4096m -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError"

3 监控核心指标

# 使用JVisualVM远程连接
jmxremote.port=1099
jmxremote.ssl=false
jmxremote.authenticate=false

QA:部署中最容易踩的6个坑

Q1:明明删掉了旧War,为何还会打包多次? A:因为webapps/目录下的同名文件夹残留导致热加载多次,必须执行双重删除rm -rf myapp myapp.war

Q2:开发时正常,部署后报ClassNotFoundException A:开发IDE会自动加载target/目录,但Tomcat不会,检查WEB-INF/classes是否存在编译产物,或用mvn clean package重新构建。

Q3:数据库连接失败,但本机测试OK? A:War包内application.properties可能写死了localhost,改为jdbc:mysql://内网IP:3306/并开启MySQL远程访问。

Q4:无限重启循环(OutOfMemory)如何排查? A:查看logs/localhost.log中是否有java.lang.OutOfMemoryError,立刻加上-XX:+HeapDumpOnOutOfMemoryError,用MAT分析dump文件。

Q5:如何实现War包版本回滚? A:在webapps下保留myapp.warmyapp.war.bak. 回滚时执行:

rm -rf myapp && mv myapp.war.bak myapp.war && touch myapp.war

Q6:高并发下连接池爆满怎么办? A:修改Tomcat的maxConnections和数据库连接池(HikariCP):

spring.datasource.hikari.maximum-pool-size: 50

从War到DevOps的下一步

当War包稳定运行两周后,建议引入Jenkins + Ansible自动部署,并将部署日志输出到ELK,但基础仍然是这一套手动流程——只有理解了War的结构、Tomcat的类加载机制和上下文路径逻辑,才能在后序容器化(Docker+K8s)中游刃有余。

最后提醒一句: 每次修改server.xml前先备份,并用configtest工具验证:

/opt/tomcat/bin/configtest.sh

返回SUCCESS后再重启,能避免90%的意外宕机。

抱歉,评论功能暂时关闭!