2025 最新 | Linux 下 Java Jar 包后台运行与进程守护全攻略(从新手到生产必备)
你是不是也经历过这些“崩溃瞬间”:
- 😭 SSH 一断开,辛苦跑了好几个小时的 Jar 包直接挂掉?
- 😡 凌晨 3 点被群里疯狂 @,上线修复的却是“进程莫名消失”?
- 🤯 用
nohup java -jar xxx.jar &以为万事大吉,结果第二天早上发现日志停在昨天,磁盘还被nohup.out撑爆了……
别慌!今天这篇文章彻底帮你解决这个问题。我们将一次性讲透 6 种方式,从最原始的命令到生产环境推荐方案,附带完整对比表 + 最佳实践 + 一键启动脚本。
一、6 种方式对比表格(先看这个就懂了)
| 方式 | 命令关键点 | SSH 断开后存活 | 日志管理 | 开机自启 | 适合场景 | 推荐指数 |
|---|---|---|---|---|---|---|
| 方式1 | 直接运行 | ❌ 否 | 屏幕输出 | ❌ 否 | 本地调试 | ★☆☆☆☆ |
| 方式2 | & 后台 |
❌ 否 | 屏幕输出 | ❌ 否 | 临时测试 | ★★☆☆☆ |
| 方式3 | nohup |
✅ 是 | 差 (nohup.out) | ❌ 否 | 个人测试、临时任务 | ★★★☆☆ |
| 方式4 | nohup + 重定向 |
✅ 是 | 好 (自定义路径) | ❌ 否 | 传统服务器、中型项目 | ★★★★☆ |
| 方式5 | screen / tmux |
✅ 是 | 极好 (会话保持) | ❌ 否 | 需要频繁交互/看日志 | ★★★★★ |
| 方式6 | Systemd 服务 | ✅ 是 | 完美 (journalctl) | ✅ 支持 | 所有生产环境 | ★★★★★★★ |
二、详细讲解(强烈建议从方式 4 开始看)
❌ 方式 1 & 2:最原始的两种(只适合本地玩玩)
# 方式1:前台运行,窗口被锁定,Ctrl+C 即停止
java -jar app.jar
# 方式2:加个 & 后台运行
java -jar app.jar &
致命缺点: 当你关闭终端或 SSH 断开连接时,会话会发送
SIGHUP信号,导致进程直接被杀。结论:永远不要在服务器上这么干!
⚠️ 方式 3:经典 nohup 的“坑”
很多人习惯这么写:
nohup java -jar app.jar &
这种写法有三大隐患:
- 日志灾难: 所有输出(System.out)默认写入当前目录的
nohup.out,文件会无限增长,甚至占满磁盘空间。 - 错误丢失: 如果没有正确重定向 stderr,异常堆栈信息可能不会被记录,导致排查问题两眼一抹黑。
- 管理混乱: 多个 Jar 包混用一个 nohup.out,根本分不清谁是谁。
✅ 方式 4:nohup 的正确打开方式(2025 推荐写法)
# 先创建日志目录
mkdir -p logs
# 4.1 标准生产写法(推荐)
# 解释:
# > logs/app.log : 标准输出重定向到文件
# 2>&1 : 错误输出(2) 也重定向到标准输出(1) 去
# & : 后台运行
nohup java -Xms512m -Xmx2g -jar app.jar > logs/app.log 2>&1 &
# 4.2 按启动时间命名日志
# 注意:这只会在启动那一刻生成带日期的文件名,它不会每天自动切割!
nohup java -jar app.jar > logs/app-$(date +%F).log 2>&1 &
# 4.3 “静默”模式(不需要看日志,或者程序内部集成了 Logback/Log4j)
nohup java -jar app.jar > /dev/null 2>&1 &
🛠️ 方式 5:神器级 screen / tmux(运维最爱)
如果你需要经常连上去看控制台日志,或者需要手动输入指令交互,这两个工具是神器。它们创建了一个**“永不掉线”的虚拟终端**。
tmux 用法(比 screen 更现代化,推荐)
# 1. 创建一个叫 "myapp" 的会话
tmux new -s myapp
# 2. 在里面正常启动 Java
java -jar app.jar
# 3. 哪怕你直接关掉 SSH 窗口,程序也在跑
# 4. 下次上线,一键找回现场:
tmux attach -t myapp
🚀 方式 6:生产环境终极方案 —— Systemd 托管(强烈推荐)
别再写脚本了!用 Linux 自带的 Systemd,不仅能开机自启,还能挂了自动重启。
第一步:创建服务文件
sudo vim /etc/systemd/system/myapp.service
第二步:填入标准配置
[Unit]
Description=My Java Application
After=syslog.target network.target
[Service]
Type=simple
# 强烈建议使用非 root 用户运行
User=root
# 项目根目录
WorkingDirectory=/opt/myapp
# 启动命令 (请换成你 java 的绝对路径,可用 `which java` 查看)
ExecStart=/usr/bin/java -Xms1g -Xmx2g -jar /opt/myapp/app.jar
# 停止命令
ExecStop=/bin/kill -15 $MAINPID
# Java 进程通常以 143 状态码退出,需标记为成功,否则 Systemd 会报错
SuccessExitStatus=143
# 进程崩溃后自动重启
Restart=always
RestartSec=10
# 日志输出到 systemd journal
StandardOutput=journal
StandardError=journal
# 增加文件句柄限制
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
第三步:享受正规军的待遇
# 重新加载配置
sudo systemctl daemon-reload
# 启动服务
sudo systemctl start myapp
# 设置开机自启
sudo systemctl enable myapp
# 查看实时日志(比 tail -f 强大得多,支持时间过滤)
sudo journalctl -u myapp -f
三、实用加分技巧
1. 快速查找 Java 进程
别只知道 ps -ef 了,试试这些高效命令:
# 最精准:列出 Java 进程的完整包名
jps -l
# 最现代:根据端口查进程
ss -ltnp | grep 8080
2. 通用启动/停止脚本 (Shell)
如果你不想用 Systemd,这个脚本可以存为 run.sh,配合 Jenkins 或手动发布很方便。这里使用了更稳健的 pgrep 来获取 PID。
#!/bin/bash
# 配置区
APP_NAME=shareniu.jar
APP_PATH=/opt/shareniu
LOG_FILE=$APP_PATH/logs/app.log
# 检查 PID (使用 pgrep -f 更精准,防止 grep 到脚本自己)
PID=$(pgrep -f $APP_NAME)
start() {
if [ -n "$PID" ]; then
echo "❌ $APP_NAME 正在运行 (PID: $PID)"
else
mkdir -p $APP_PATH/logs
nohup java -Xms1g -Xmx2g -jar $APP_PATH/$APP_NAME > $LOG_FILE 2>&1 &
echo "✅ $APP_NAME 已启动"
fi
}
stop() {
if [ -n "$PID" ]; then
kill -15 $PID
echo "🛑 已发送停止信号给 $APP_NAME (PID: $PID)"
else
echo "⚠️ $APP_NAME 未运行"
fi
}
case "$1" in
start) start ;;
stop) stop ;;
restart) stop; sleep 3; start ;;
status)
if [ -n "$PID" ]; then echo "🟢 运行中 (PID: $PID)"; else echo "⚪ 未运行"; fi
;;
*) echo "用法: $0 {start|stop|restart|status}" ;;
esac
四、总结与建议
| 你的场景 | 推荐方案 |
|---|---|
| 本地开发/调试 | 直接 IDE 运行 或 命令行直连 |
| 个人服务器/小工具 | tmux (最方便) 或 nohup |
| 公司生产环境 | Systemd (唯一正解) |
| Docker/K8s 容器 | 方式 1 (直接 java -jar,必须前台运行) |
2025 年了,答应我:
如果是正式的 Linux 服务器,尽量抛弃 nohup,拥抱 Systemd。它提供的崩溃重启、开机自启和日志管理能力,能让你少熬很多个通宵!
你们公司现在用哪种方式跑 Jar 包?是还在坚持 nohup,还是已经全面容器化了?欢迎评论区交流~
点赞 + 收藏,下次部署服务时不迷路!🚀