#!/bin/bash
|
|
|
|
# ========================================
|
|
# Java应用启动/重启脚本
|
|
# 使用方法: ./restart-java-app.sh
|
|
# ========================================
|
|
|
|
# ========================================
|
|
# 配置参数 - 请根据实际情况修改
|
|
# ========================================
|
|
JAR_NAME="" # JAR包名称(留空则自动检测)
|
|
PORT=8080 # 应用端口号
|
|
|
|
# ========================================
|
|
# 其他配置(一般不需要修改)
|
|
# ========================================
|
|
JAVA_OPTS="-Xms512m -Xmx1024m" # JVM参数
|
|
LOG_FILE="app.log" # 日志文件名
|
|
PID_FILE="app.pid" # PID文件名
|
|
|
|
# 颜色输出
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# ========================================
|
|
# 函数定义
|
|
# ========================================
|
|
|
|
# 打印带颜色的消息
|
|
print_message() {
|
|
local color=$1
|
|
local message=$2
|
|
echo -e "${color}[$(date '+%Y-%m-%d %H:%M:%S')] ${message}${NC}"
|
|
}
|
|
|
|
# 检查JAR文件是否存在
|
|
check_jar_exists() {
|
|
# 如果JAR_NAME为空,自动检测当前目录下的JAR文件
|
|
if [ -z "$JAR_NAME" ]; then
|
|
local jar_files=(*.jar)
|
|
local jar_count=${#jar_files[@]}
|
|
|
|
# 检查是否存在JAR文件
|
|
if [ ! -f "${jar_files[0]}" ]; then
|
|
print_message $RED "错误: 当前目录下没有找到JAR文件!"
|
|
print_message $YELLOW "请将JAR文件放在脚本同一目录下,或在脚本中指定JAR_NAME"
|
|
exit 1
|
|
fi
|
|
|
|
# 如果只有一个JAR文件,自动使用它
|
|
if [ $jar_count -eq 1 ]; then
|
|
JAR_NAME="${jar_files[0]}"
|
|
print_message $BLUE "自动检测到JAR文件: $JAR_NAME"
|
|
else
|
|
print_message $RED "错误: 当前目录下有多个JAR文件,请在脚本中指定JAR_NAME:"
|
|
for jar in "${jar_files[@]}"; do
|
|
print_message $YELLOW " - $jar"
|
|
done
|
|
exit 1
|
|
fi
|
|
else
|
|
# 检查指定的JAR文件是否存在
|
|
if [ ! -f "$JAR_NAME" ]; then
|
|
print_message $RED "错误: JAR文件 '$JAR_NAME' 不存在!"
|
|
print_message $YELLOW "请检查JAR_NAME配置是否正确,或确保JAR文件在当前目录下"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 检查端口是否被占用
|
|
check_port() {
|
|
local port=$1
|
|
if command -v netstat >/dev/null 2>&1; then
|
|
netstat -tlnp 2>/dev/null | grep ":$port " >/dev/null
|
|
elif command -v ss >/dev/null 2>&1; then
|
|
ss -tlnp | grep ":$port " >/dev/null
|
|
else
|
|
# 如果没有netstat和ss,尝试使用lsof
|
|
if command -v lsof >/dev/null 2>&1; then
|
|
lsof -i :$port >/dev/null 2>&1
|
|
else
|
|
return 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 获取运行中的应用PID
|
|
get_app_pid() {
|
|
if [ -f "$PID_FILE" ]; then
|
|
local pid=$(cat "$PID_FILE")
|
|
# 检查进程是否真的在运行
|
|
if ps -p $pid > /dev/null 2>&1; then
|
|
echo $pid
|
|
else
|
|
# PID文件存在但进程不存在,删除PID文件
|
|
rm -f "$PID_FILE"
|
|
echo ""
|
|
fi
|
|
else
|
|
# 通过进程名查找
|
|
pgrep -f "$JAR_NAME" | head -1
|
|
fi
|
|
}
|
|
|
|
# 停止应用
|
|
stop_app() {
|
|
local pid=$(get_app_pid)
|
|
|
|
if [ -z "$pid" ]; then
|
|
print_message $YELLOW "应用未运行"
|
|
return 0
|
|
fi
|
|
|
|
print_message $YELLOW "正在停止应用 (PID: $pid)..."
|
|
|
|
# 优雅停止
|
|
kill $pid
|
|
|
|
# 等待进程停止
|
|
local count=0
|
|
while [ $count -lt 30 ]; do
|
|
if ! ps -p $pid > /dev/null 2>&1; then
|
|
print_message $GREEN "应用已成功停止"
|
|
rm -f "$PID_FILE"
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
count=$((count + 1))
|
|
done
|
|
|
|
# 如果优雅停止失败,强制停止
|
|
print_message $YELLOW "优雅停止超时,强制停止应用..."
|
|
kill -9 $pid 2>/dev/null
|
|
|
|
sleep 2
|
|
if ! ps -p $pid > /dev/null 2>&1; then
|
|
print_message $GREEN "应用已强制停止"
|
|
rm -f "$PID_FILE"
|
|
return 0
|
|
else
|
|
print_message $RED "停止应用失败"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# 启动应用
|
|
start_app() {
|
|
print_message $BLUE "正在启动应用..."
|
|
|
|
# 检查端口是否被占用
|
|
if check_port $PORT; then
|
|
print_message $RED "端口 $PORT 已被占用,请检查是否有其他应用在使用该端口"
|
|
return 1
|
|
fi
|
|
|
|
# 启动应用
|
|
nohup java $JAVA_OPTS -jar "$JAR_NAME" --server.port=$PORT > "$LOG_FILE" 2>&1 &
|
|
local pid=$!
|
|
|
|
# 保存PID
|
|
echo $pid > "$PID_FILE"
|
|
|
|
# 等待应用启动
|
|
print_message $BLUE "等待应用启动..."
|
|
sleep 3
|
|
|
|
# 检查进程是否还在运行
|
|
if ps -p $pid > /dev/null 2>&1; then
|
|
# 检查端口是否监听
|
|
local count=0
|
|
while [ $count -lt 30 ]; do
|
|
if check_port $PORT; then
|
|
print_message $GREEN "应用启动成功!"
|
|
print_message $GREEN "PID: $pid"
|
|
print_message $GREEN "端口: $PORT"
|
|
print_message $GREEN "日志文件: $LOG_FILE"
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
count=$((count + 1))
|
|
done
|
|
|
|
print_message $YELLOW "应用进程已启动,但端口 $PORT 未监听,请检查日志文件: $LOG_FILE"
|
|
return 1
|
|
else
|
|
print_message $RED "应用启动失败,请检查日志文件: $LOG_FILE"
|
|
rm -f "$PID_FILE"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# 显示应用状态
|
|
show_status() {
|
|
local pid=$(get_app_pid)
|
|
|
|
if [ -n "$pid" ]; then
|
|
print_message $GREEN "应用正在运行"
|
|
print_message $GREEN "PID: $pid"
|
|
print_message $GREEN "端口: $PORT"
|
|
|
|
if check_port $PORT; then
|
|
print_message $GREEN "端口状态: 正在监听"
|
|
else
|
|
print_message $YELLOW "端口状态: 未监听"
|
|
fi
|
|
else
|
|
print_message $YELLOW "应用未运行"
|
|
fi
|
|
}
|
|
|
|
# 显示帮助信息
|
|
show_help() {
|
|
echo "Java应用管理脚本"
|
|
echo ""
|
|
echo "使用方法:"
|
|
echo " $0 [选项]"
|
|
echo ""
|
|
echo "选项:"
|
|
echo " start 启动应用"
|
|
echo " stop 停止应用"
|
|
echo " restart 重启应用"
|
|
echo " status 显示应用状态"
|
|
echo " help 显示帮助信息"
|
|
echo ""
|
|
echo "配置:"
|
|
echo " JAR包名称: ${JAR_NAME:-"自动检测"}"
|
|
echo " 端口号: $PORT"
|
|
echo ""
|
|
echo "注意: 如果目录下只有一个JAR文件,可以将JAR_NAME留空实现自动检测"
|
|
}
|
|
|
|
# ========================================
|
|
# 主程序
|
|
# ========================================
|
|
|
|
# 检查JAR文件是否存在
|
|
check_jar_exists
|
|
|
|
# 处理命令行参数
|
|
case "${1:-restart}" in
|
|
"start")
|
|
start_app
|
|
;;
|
|
"stop")
|
|
stop_app
|
|
;;
|
|
"restart")
|
|
print_message $BLUE "重启应用..."
|
|
stop_app
|
|
if [ $? -eq 0 ]; then
|
|
sleep 2
|
|
start_app
|
|
else
|
|
print_message $RED "停止应用失败,取消重启"
|
|
exit 1
|
|
fi
|
|
;;
|
|
"status")
|
|
show_status
|
|
;;
|
|
"help"|"-h"|"--help")
|
|
show_help
|
|
;;
|
|
*)
|
|
print_message $RED "未知选项: $1"
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|