Shell脚本实战:编写一个通用的Java服务启停管理脚本

发布时间:2026/7/29 19:02:50

Shell脚本实战:编写一个通用的Java服务启停管理脚本 1. 引言在日常运维或本地开发中我们经常需要启动、停止、重启 Java 应用并检查其运行状态。如果每次都手动敲一长串java -jar命令不仅麻烦而且容易出错。一个好的实践是把这些操作封装成一个可靠的 Shell 脚本。本文将以一个实际可运行的 Bash 脚本为例详细拆解其设计思路、关键函数与使用场景。你可以直接复用这个模板稍作修改就能适配自己的 Spring Boot 或任何可执行 Jar 项目。2. 脚本总览与设计目标脚本的核心功能包括前台启动直接在当前终端运行方便查看实时日志。后台启动-d 参数以后台守护进程方式启动自动记录 PID失败时输出错误日志。安全停止先尝试kill正常终止超时后使用kill -9强制停止。重启组合停止与启动。状态查询快速判断服务是否正在运行。防重复启动通过 PID 文件检测已运行实例避免端口冲突。脚本统一通过case $1解析命令行参数并提供友好的Usage帮助。3. 环境变量与目录准备APP_NAMEappJARapp.jarBASE_DIR$(cd$(dirname$0);pwd)PID_DIR$BASE_DIR/runPID_FILE$PID_DIR/app.pidLOG_FILE$PID_DIR/start.logJAVA_OPTS-Xms512m -Xmx512mmkdir-p$PID_DIRBASE_DIR脚本所在目录保证无论从哪里执行都能正确定位到 jar 包。PID_DIR统一把进程 ID 文件和日志放在run/子目录下保持目录整洁。JAVA_OPTS默认堆内存 512M可按需调整例如加上-Dspring.profiles.activeprod等参数。4. 核心函数解析4.1is_running()—— 判断运行状态is_running(){if[-f$PID_FILE];thenPID$(cat$PID_FILE)ifps-p$PID/dev/null21;thenreturn0fifireturn1}先检查 PID 文件是否存在再通过ps -p验证该进程是否真实存在。这样可以避免因异常退出而残留的僵尸 PID 文件导致误判。4.2start_foreground()—— 前台启动start_foreground(){ifis_running;thenechoAlready running (PID$(cat$PID_FILE))exit0fiechoStarting...java$JAVA_OPTS-jar$BASE_DIR/$JARPID$!echo$PID$PID_FILEwait$PIDrm-f$PID_FILE}虽然是“前台启动”但底层仍使用并把进程放入后台再通过wait阻塞脚本本身这样终端看起来就像前台运行一样。进程退出后自动清理 PID 文件。不过实际使用时更多会采用下面的后台模式。4.3start_background()—— 后台守护启动start_background(){ifis_running;thenechoAlready running (PID$(cat$PID_FILE))exit0firm-f$LOG_FILEsetsid\java$JAVA_OPTS-jar$BASE_DIR/$JAR\$LOG_FILE21/dev/nullPID$!echo$PID$PID_FILEsleep2ifps-p$PID/dev/null21;thenrm-f$LOG_FILEechoStarted.echoPID$PIDelseechoStart failed.if[-f$LOG_FILE];thencat$LOG_FILEfirm-f$PID_FILEfi}这里的几个关键点setsid让 Java 进程脱离当前终端会话即使关闭终端服务也不会中断。标准输入重定向到/dev/null标准输出和标准错误写入$LOG_FILE。启动后sleep 2再检查进程是否存活做到快速失败检测。如果进程已退出说明启动失败此时输出错误日志帮助排查。启动成功后删除临时日志文件保持目录干净。4.4stop_app()—— 优雅停止与强制终止stop_app(){if!is_running;thenechoNot running.rm-f$PID_FILEreturnfiPID$(cat$PID_FILE)echoStopping...kill$PIDforiin{1..20};doif!ps-p$PID/dev/null21;thenbreakfisleep1doneifps-p$PID/dev/null21;thenechoForce kill.kill-9$PIDfirm-f$PID_FILEechoStopped.}优雅停止流程先发送TERM信号给应用一个执行ShutdownHook的机会。循环等待最多 20 秒每秒检查一次是否退出。若超时仍未退出使用kill -9强制终止。最后清理 PID 文件。4.5status_app()—— 查看状态status_app(){ifis_running;thenechoRunning (PID$(cat$PID_FILE))elseechoStoppedfi}简单明了用于集成到监控系统或人工巡检。5. 命令行入口与模式选择case$1instart)if[$2-d];thenstart_backgroundelseexecjava$JAVA_OPTS-jar$BASE_DIR/$JARfi;;restart)stop_appsleep1if[$2-d];thenstart_backgroundelseexecjava$JAVA_OPTS-jar$BASE_DIR/$JARfi;;stop)stop_app;;status)status_app;;*)catEOF Usage: ./app.sh start ./app.sh start -d ./app.sh restart ./app.sh restart -d ./app.sh stop ./app.sh status EOF;;esacexec java …是关键对于前台启动/重启脚本会把自己替换为 Java 进程让 Java 直接成为当前终端的前台进程。这样CtrlC可以直接终止应用日志也会直接打印在当前终端开发调试非常方便。后台模式由-d参数触发调用start_background()。帮助信息在参数错误时自动展示。6. 实际使用示例将脚本保存为app.sh放在 jar 包同级目录赋予执行权限chmodx app.sh开发调试前台看到实时日志./app.sh start生产环境后台守护./app.sh start-d重启或滚动更新./app.sh restart-d查看运行状态./app.sh status停止服务./app.sh stop7. 扩展建议这个脚本非常容易扩展可以根据实际需求进行增强多环境配置通过-p参数传入 Spring profile动态拼接到JAVA_OPTS中。GC 日志与 jvm dump添加-XX:HeapDumpOnOutOfMemoryError等参数。健康检查在start_background()中增加curl检测接口是否真正就绪。日志滚动借助rotatelogs或直接由应用框架如 Logback管理。集成 systemd在 systemd service 文件中调用脚本的start/stop使应用开机自启。8. 总结本文提供的一个 Bash 管理脚本通过 PID 文件、setsid、kill超时检测等机制实现了对 Java 服务“启动、停止、重启、状态查询”的完整生命周期管理。它既保留了exec带来的前台调试便利又支持-d后台守护模式非常适合作为 Spring Boot 或独立 Jar 应用的标准化运维脚本。你可以直接复制这个模板修改APP_NAME、JAR和JAVA_OPTS三个变量就能快速为自己的项目生成一个可靠的启停脚本。

相关新闻