本文目录导读:

统一 Java 项目部署结构,核心目标是标准化、可追溯、易运维,一个清晰的部署结构能显著降低环境差异导致的问题,并便于 CI/CD 集成。
下面从通用规范、主流场景(Spring Boot、传统 Tomcat、Docker)和最佳实践三个层面为你详细说明。
核心原则与通用结构
无论使用哪种框架,都应该遵循以下逻辑结构:
/opt/app/ # 应用根目录(通常是 /opt/app/<应用名>) ├── bin/ # 启动、停止、重启脚本 │ ├── startup.sh │ ├── shutdown.sh │ └── health_check.sh ├── conf/ # 配置文件(外置,不打包在 jar/war 里) │ ├── application.yml (或 application.properties) │ ├── logback-spring.xml │ └── nginx.conf ├── lib/ # 核心程序包 │ └── myapp.jar (或 myapp.war) ├── logs/ # 运行日志(按日期滚动) │ ├── catalina.out (Tomcat) │ ├── spring.log │ └── gc.log ├── data/ # 运行时产生的数据(如临时文件、上传目录) ├── backup/ # 备份(部署前的旧版本备份) └── .version / .env # 版本记录文件
关键点:
conf/、logs/、data/必须独立于程序包,才能实现“配置外置”和“无状态部署”。
按场景统一部署结构
Spring Boot(JAR 方式部署,最推荐)
Spring Boot 内嵌了 Tomcat,部署非常简单。
目标结构示例 (/opt/app/order-service/):
order-service/
├── bin/
│ ├── startup.sh # 启动:nohup java -jar -Dspring.config.location=../conf/ ../lib/order-service.jar > ../logs/startup.log &
│ ├── shutdown.sh # 优雅停机:kill -15 `cat ../logs/pid.pid`
│ └── metrics.sh # 健康检查:curl http://localhost:8080/actuator/health
├── conf/
│ ├── application-prod.yml # 生产环境配置(重点:数据库、Redis、端口等)
│ ├── application-common.yml # 公共配置
│ └── logback.xml
├── lib/
│ └── order-service-1.2.3.jar
├── logs/
│ ├── order-service.log
│ └── gc.log (通过 JVM 参数 -Xloggc:../logs/gc.log 生成)
├── data/
│ └── upload/
├── backup/
│ └── order-service-1.2.2.jar.bak
└── .version
└── DEPLOY_VERSION=1.2.3
启动脚本示例 (startup.sh):
#!/bin/bash
APP_HOME=$(cd "$(dirname "$0")/.." && pwd)
JAR_PATH="$APP_HOME/lib/*.jar"
LOG_PATH="$APP_HOME/logs/startup.log"
PID_FILE="$APP_HOME/logs/pid.pid"
# 特别注意:配置外置 + 日志路径外置 + 生成 PID
nohup java -server -Xms1g -Xmx1g \
-XX:+UseG1GC -Xloggc:"$APP_HOME/logs/gc.log" \
-jar "$JAR_PATH" \
--spring.config.location="$APP_HOME/conf/application-prod.yml" \
--logging.config="$APP_HOME/conf/logback.xml" \
--logging.file.path="$APP_HOME/logs" \
> /dev/null 2>&1 &
echo $! > "$PID_FILE"
echo "Application started, PID: $(cat $PID_FILE)"
传统 Tomcat(WAR 方式部署,已逐步被取代)
适用于老旧项目或必须使用外置容器的场景。
目标结构示例 (/opt/app/myapp/):
myapp/
├── bin/
│ ├── startup.sh # 自定义启动:调用 Tomcat 的 startup.sh 并指定 CATALINA_BASE
│ └── shutdown.sh
├── conf/ # 注意:这是应用的配置文件,不是 Tomcat 的
│ ├── db.properties
│ └── log4j2.xml
├── lib/
│ └── myapp.war
├── logs/
├── data/
└── tomcat/ # 一个隔离的 Tomcat 实例
├── bin/
├── conf/ # server.xml 中指定 docBase 指向 ../lib/myapp.war
├── logs/
├── webapps/
└── work/
要点:每个应用使用独立的
CATALINA_BASE,避免多个 war 共享一个 Tomcat 导致配置冲突。
Docker 容器化部署(现代标准)
容器化后,结构更清晰,但镜像是不可变的。
Dockerfile 示例:
FROM openjdk:17-jre-slim
# 1. 在镜像内创建标准目录
WORKDIR /opt/app
RUN mkdir -p /opt/app/{bin,conf,logs,data}
# 2. 复制启动脚本和程序包
COPY bin/startup.sh ./bin/
COPY lib/app.jar ./lib/
COPY conf/application.yml ./conf/
# 3. 声明挂载点(运行时挂载宿主机目录)
VOLUME ["/opt/app/conf", "/opt/app/logs", "/opt/app/data"]
EXPOSE 8080
CMD ["bin/startup.sh"]
启动时的目录映射:
docker run -d \
--name order-service \
-p 8080:8080 \
-v /opt/app/order-service/conf:/opt/app/conf:ro \
-v /opt/app/order-service/logs:/opt/app/logs \
-v /opt/app/order-service/data:/opt/app/data \
your-image:1.2.3
统一部署的最佳实践
-
配置外置(12-Factor App 原则)
- 配置文件不要打包在 JAR 里,通过
--spring.config.location或环境变量指定。 - 数据库密码、密钥等敏感信息使用环境变量或 Vault 管理,不要写在
application.yml里。
- 配置文件不要打包在 JAR 里,通过
-
日志标准化
- 所有应用日志统一输出到
/opt/app/<应用名>/logs/。 - 使用 Logback 或 Log4j2,并启用按日期和大小滚动。
- 固定日志模式:
时间 | 线程 | 日志级别 | 类名 | 请求ID(traceId) | 消息。
- 所有应用日志统一输出到
-
启动脚本标准化
- 每个应用必须有
startup.sh、shutdown.sh、health_check.sh。 startup.sh必须:设置 JVM 参数、生成 PID 文件、自动重启必要组件。shutdown.sh应该使用kill -15(优雅停机),而不是kill -9。
- 每个应用必须有
-
版本与回滚
- 部署前,将当前版本备份到
backup/目录。 - 部署后,在
.version文件中记录当前版本号。 - 回滚命令:
stop -> mv lib/old.jar lib/current.jar -> start。
- 部署前,将当前版本备份到
-
目录权限最小化
logs/、data/:应用运行用户需要读写权限。conf/:应用运行用户只需要读权限(chmod 744)。bin/:需要执行权限(chmod 755)。lib/:只需要读权限。
-
集中式部署工具
- 使用 Ansible、SaltStack 或 Jenkins Pipeline 等工具将上述结构模板化。
- 工具自动执行:创建目录 -> 拷贝启动脚本 -> 上传 JAR -> 重启 -> 健康检查。
一个统一的部署结构模板
无论你使用什么技术栈,最终可以落地的目录结构如下:
/opt/app/<app_name>/ ├── bin/ │ ├── startup.sh # 启动(带 JVM 参数、PID 记录) │ ├── shutdown.sh # 优雅停机 │ └── health_check.sh # 返回 200 OK ├── conf/ │ ├── application.yml # 环境相关配置 │ └── logback.xml ├── lib/ │ └── <app_name>.jar # 唯一程序包 ├── logs/ │ ├── catalina.out # 如果使用 Tomcat │ ├── app.log # 应用日志 │ └── gc.log ├── data/ # 运行时数据 ├── backup/ # 旧版本备份 └── .version # 版本记录
采用这个结构,配合 CI/CD 管道(Jenkins、GitLab CI 等),就能实现一次构建、多次部署、随处运行的统一目标。