linux部署
大约 7 分钟安装与部署
极简后台运行
nohup 表示后台运行,后面的 anhuifuyang.log 表示输出的日期写入该文件
nohup java -jar anhuifuyang.jar > anhuifuyang.log &
查看java进程
查看本地所有java进程
将下面代码保存为 java_process_check.sh ,运行后查看本地所有 java 进程
#!/bin/bash
# 检查Java进程和端口脚本
echo "正在扫描Java进程和端口信息..."
echo "=============================================="
# 检查是否以root运行,如果不是则提示
if [[ $EUID -ne 0 ]]; then
echo "注意: 非root用户运行可能无法查看所有进程的完整信息"
echo "=============================================="
fi
# 查找所有Java进程
java_pids=$(ps -ef | grep java | grep -v grep | awk '{print $2}')
if [[ -z "$java_pids" ]]; then
echo "未找到任何Java进程"
exit 0
fi
# 计数器
count=0
# 遍历每个Java进程
for pid in $java_pids; do
((count++))
echo "Java进程 #$count:"
echo "----------------------------------------------"
# 获取进程基本信息
process_info=$(ps -p $pid -o pid,user,pcpu,pmem,cmd --no-headers 2>/dev/null)
if [[ -z "$process_info" ]]; then
echo "进程 $pid 不存在或无法访问"
echo ""
continue
fi
# 显示进程基本信息
echo "PID: $(echo $process_info | awk '{print $1}')"
echo "用户: $(echo $process_info | awk '{print $2}')"
echo "CPU: $(echo $process_info | awk '{print $3}')%"
echo "内存: $(echo $process_info | awk '{print $4}')%"
# 获取完整的命令行
cmd_line=$(cat /proc/$pid/cmdline 2>/dev/null | tr '\0' ' ')
if [[ -n "$cmd_line" ]]; then
# 提取jar文件路径
jar_path=$(echo "$cmd_line" | grep -o -E '[^ ]+\.jar' | head -1)
if [[ -n "$jar_path" ]]; then
# 如果找到的是相对路径,尝试转换为绝对路径
if [[ "$jar_path" != /* ]]; then
# 获取进程的工作目录
cwd=$(readlink /proc/$pid/cwd 2>/dev/null)
if [[ -n "$cwd" ]]; then
absolute_jar_path="${cwd}/${jar_path}"
if [[ -f "$absolute_jar_path" ]]; then
jar_path="$absolute_jar_path"
fi
fi
fi
echo "JAR路径: $jar_path"
else
echo "JAR路径: 未找到或不是jar启动"
# 显示主类信息
main_class=$(echo "$cmd_line" | grep -o -E '([a-zA-Z0-9_]+\.)+[a-zA-Z0-9_]+' | head -1)
if [[ -n "$main_class" ]]; then
echo "主类: $main_class"
fi
fi
# 显示完整的命令行(截断过长的行)
echo "命令行: $(echo "$cmd_line" | cut -c1-100)$(if [ ${#cmd_line} -gt 100 ]; then echo "..."; fi)"
else
echo "JAR路径: 无法获取进程信息"
fi
# 获取进程使用的端口
echo "端口:"
ports=$(ss -tlnp 2>/dev/null | awk -v pid=$pid '$7 ~ pid {print $4}' | awk -F: '{print $NF}' | sort -nu)
if [[ -n "$ports" ]]; then
echo "$ports" | while read port; do
echo " - $port"
done
else
# 尝试使用netstat作为备选
ports=$(netstat -tlnp 2>/dev/null | awk -v pid=$pid '$7 ~ pid {split($4, a, ":"); print a[length(a)]}' | sort -nu)
if [[ -n "$ports" ]]; then
echo "$ports" | while read port; do
echo " - $port"
done
else
echo " - 未找到监听的TCP端口"
fi
fi
# 获取进程启动时间
start_time=$(ps -p $pid -o lstart --no-headers 2>/dev/null)
if [[ -n "$start_time" ]]; then
echo "启动时间: $start_time"
fi
echo ""
done
echo "=============================================="
echo "总共找到 $count 个Java进程"
# 显示端口汇总信息
echo ""
echo "端口汇总:"
echo "----------------------------------------------"
all_ports=$(ss -tlnp 2>/dev/null | grep java | awk '{print $4}' | awk -F: '{print $NF}' | sort -nu)
if [[ -n "$all_ports" ]]; then
echo "$all_ports" | while read port; do
# 获取使用该端口的进程信息
using_pids=$(ss -tlnp 2>/dev/null | awk -v port=":$port" '$4 ~ port {print $7}' | cut -d= -f2 | cut -d, -f1 | sort -u)
echo "端口 $port 被进程: $using_pids 使用"
done
else
echo "未找到Java进程监听的端口"
fi
echo "=============================================="
非systemctl
某次在 centos7 中为 FineReport 制作 systemctl 管理的守护进程时出现异常情况:使用命令启动后,查看日志,发现 FineReport 一直在自己重启,导致前端无法使用,后来换成 bash 脚本管理启停就没有问题了。下面是后来通过 AI 制作的脚本工具,修改文件开头的多个参数后可生成管理 java 进程的启停脚本
生成启停管理脚本
#!/bin/bash
# ==========================================
# 🚀 Java 启停脚本生成器
# ==========================================
# 1. 基础配置区域 (每次有新项目只需修改这里)
APP_NAME="expenseTracker" # 项目名称
JAR_FULL_PATH="/projs/expenseTracker/backend/expenseTracker.jar" # JAR包绝对路径
CONFIG_FULL_PATH="/projs/expenseTracker/backend/application.yml" # 配置文件绝对路径
OUTPUT_BIN_DIR="/projs/expenseTracker/sh" # 生成的脚本存放目录
LOG_DIR="/var/log" # 日志存放目录
PID_DIR="/var/run" # PID存放目录
# 2. JVM 参数配置,修改项目占用内存大小
JAVA_OPTS="-Xms512m -Xmx512m -Dspring.config.location=${CONFIG_FULL_PATH}"
# ==========================================
# 👇 以下为生成逻辑,通常不需要修改
# ==========================================
# 自动解析路径
JAR_FILE_NAME=$(basename "$JAR_FULL_PATH")
JAR_FILE_PATH=$(dirname "$JAR_FULL_PATH")
# 确保输出目录存在
mkdir -p "$OUTPUT_BIN_DIR"
echo "开始为项目 [$APP_NAME] 生成管理脚本..."
# ------------------------------------------
# 生成 start.sh
# ------------------------------------------
START_SCRIPT_PATH="$OUTPUT_BIN_DIR/start-${APP_NAME}.sh"
cat << EOF > "$START_SCRIPT_PATH"
#!/bin/bash
# 启动脚本配置 (自动生成)
APP_NAME="${APP_NAME}"
JAR_FILE_NAME="${JAR_FILE_NAME}"
JAR_FILE_PATH="${JAR_FILE_PATH}"
JAR_PATH="${JAR_FULL_PATH}"
CONFIG_FILE="${CONFIG_FULL_PATH}"
LOG_FILE="${LOG_DIR}/${APP_NAME}.log"
STARTUP_LOG="${LOG_DIR}/${APP_NAME}-startup.log"
PID_FILE="${PID_DIR}/${APP_NAME}.pid"
JAVA_OPTS="${JAVA_OPTS}"
$(cat << 'BODY'
# 检查必要文件是否存在
if [ ! -f "$JAR_PATH" ]; then
echo "$(date): 错误: 找不到 JAR 文件: $JAR_PATH" >> "$STARTUP_LOG"
exit 1
fi
if [ ! -f "$CONFIG_FILE" ]; then
echo "$(date): 警告: 找不到配置文件: $CONFIG_FILE" >> "$STARTUP_LOG"
fi
# 检查 Java 是否安装
if ! command -v java &> /dev/null; then
echo "$(date): 错误: Java 未安装" >> "$STARTUP_LOG"
exit 1
fi
# 检查是否已在运行
if [ -f "$PID_FILE" ]; then
OLD_PID=$(cat "$PID_FILE")
if ps -p "$OLD_PID" > /dev/null 2>&1; then
echo "$(date): 警告: $APP_NAME 已在运行 (PID: $OLD_PID)" >> "$STARTUP_LOG"
exit 1
else
echo "$(date): 清理陈旧的 PID 文件" >> "$STARTUP_LOG"
rm -f "$PID_FILE"
fi
fi
# 切换到项目目录
cd "$JAR_FILE_PATH" || exit 1
# 启动应用
echo "$(date): 启动 $APP_NAME 服务..." >> "$STARTUP_LOG"
nohup java $JAVA_OPTS -jar "$JAR_FILE_NAME" >> "$LOG_FILE" 2>&1 &
# 记录进程 ID
PID=$!
echo $PID > "$PID_FILE"
echo "$(date): $APP_NAME 服务启动完成,PID: $PID" >> "$STARTUP_LOG"
# 验证进程是否在运行
sleep 3
if ps -p "$PID" > /dev/null 2>&1; then
echo "$(date): 验证: 进程 $PID 正在运行" >> "$STARTUP_LOG"
else
echo "$(date): 错误: 进程 $PID 启动后立即退出" >> "$STARTUP_LOG"
rm -f "$PID_FILE"
exit 1
fi
BODY
)
EOF
echo "✅ 生成成功: $START_SCRIPT_PATH"
# ------------------------------------------
# 生成 stop.sh
# ------------------------------------------
STOP_SCRIPT_PATH="$OUTPUT_BIN_DIR/stop-${APP_NAME}.sh"
cat << EOF > "$STOP_SCRIPT_PATH"
#!/bin/bash
# 关闭脚本配置 (自动生成)
APP_NAME="${APP_NAME}"
PID_FILE="${PID_DIR}/${APP_NAME}.pid"
LOG_FILE="${LOG_DIR}/${APP_NAME}.log"
SHUTDOWN_LOG="${LOG_DIR}/${APP_NAME}-shutdown.log"
$(cat << 'BODY'
# 记录关闭开始时间
echo "$(date): 开始停止 $APP_NAME 服务..." >> "$SHUTDOWN_LOG"
# 方法1: 通过 PID 文件停止进程
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if ps -p "$PID" > /dev/null 2>&1; then
echo "$(date): 通过 PID 文件找到进程 $PID,正在停止..." >> "$SHUTDOWN_LOG"
kill "$PID"
# 等待进程结束,最多30秒
TIMEOUT=30
while [ $TIMEOUT -gt 0 ] && ps -p "$PID" > /dev/null 2>&1; do
sleep 1
TIMEOUT=$((TIMEOUT-1))
done
# 如果进程还在,强制杀死
if ps -p "$PID" > /dev/null 2>&1; then
echo "$(date): 正常停止失败,强制杀死进程 $PID..." >> "$SHUTDOWN_LOG"
kill -9 "$PID"
sleep 2
fi
# 确认进程已停止
if ps -p "$PID" > /dev/null 2>&1; then
echo "$(date): 错误: 无法停止进程 $PID" >> "$SHUTDOWN_LOG"
exit 1
else
echo "$(date): 成功停止进程 $PID" >> "$SHUTDOWN_LOG"
rm -f "$PID_FILE"
fi
else
echo "$(date): 警告: PID 文件存在但进程 $PID 未运行" >> "$SHUTDOWN_LOG"
rm -f "$PID_FILE"
fi
else
echo "$(date): 警告: 未找到 PID 文件 $PID_FILE" >> "$SHUTDOWN_LOG"
fi
BODY
)
EOF
echo "✅ 生成成功: $STOP_SCRIPT_PATH"
# ------------------------------------------
# 生成 service.sh
# ------------------------------------------
SERVICE_SCRIPT_PATH="$OUTPUT_BIN_DIR/${APP_NAME}-service.sh"
cat << EOF > "$SERVICE_SCRIPT_PATH"
#!/bin/bash
# 服务管理脚本 (自动生成)
SCRIPT_DIR="\$(cd "\$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
START_SCRIPT="${START_SCRIPT_PATH}"
STOP_SCRIPT="${STOP_SCRIPT_PATH}"
PID_FILE="${PID_DIR}/${APP_NAME}.pid"
APP_NAME="${APP_NAME}"
JAR_FILE_NAME="${JAR_FILE_NAME}"
$(cat << 'BODY'
case "$1" in
start)
echo "启动 $APP_NAME 服务..."
"$START_SCRIPT"
;;
stop)
echo "停止 $APP_NAME 服务..."
"$STOP_SCRIPT"
;;
restart)
echo "重启 $APP_NAME 服务..."
"$STOP_SCRIPT"
sleep 3
"$START_SCRIPT"
;;
status)
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if ps -p "$PID" > /dev/null 2>&1; then
echo "$APP_NAME 正在运行 (PID: $PID)"
exit 0
else
echo "$APP_NAME PID 文件存在但进程未运行"
exit 1
fi
else
# 检查是否有通过其他方式启动的进程
PROCESSES=$(ps aux | grep "$JAR_FILE_NAME" | grep -v grep)
if [ -n "$PROCESSES" ]; then
echo "$APP_NAME 在运行但没有 PID 文件:"
echo "$PROCESSES"
exit 0
else
echo "$APP_NAME 未运行"
exit 3
fi
fi
;;
*)
echo "用法: $0 {start|stop|restart|status}"
exit 1
;;
esac
BODY
)
EOF
echo "✅ 生成成功: $SERVICE_SCRIPT_PATH"
# ------------------------------------------
# 赋予可执行权限
# ------------------------------------------
chmod +x "$START_SCRIPT_PATH" "$STOP_SCRIPT_PATH" "$SERVICE_SCRIPT_PATH"
echo "🎉 全部脚本生成完毕并已赋予执行权限!"
echo "👉 您可以使用以下命令管理服务:"
echo " $SERVICE_SCRIPT_PATH start|stop|restart|status"
制作守护进程
创建服务文件
在路径 /usr/lib/systemd/system 下创建名称为 huachongjin.service 的文件,内容如下,注意要配置真实的 java 路径以及项目路径
[Unit]
Description=imooc datav screen # 服务描述,自定义
After=syslog.target
[Service]
Type=forking # 表示后台执行
# -DSERVICE_LOG_FOLDER 表示日志文件的存放路径
# --spring.config.location 表示使用的配置文件所在的路径
# 推荐使用外部配置文件的方式,万一端口号冲突方便修改
ExecStart=/usr/local/java/bin/java -DSERVICE_LOG_FOLDER=/projs/imooc-datav/logs -jar /projs/imooc-datav/imooc-datav.jar --spring.config.location=/projs/imooc-datav/application-mult.yml
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
指定 jvm 参数
守护进程服务文件中运行项目时也可指定 jvm 参数
ExecStart=/usr/bin/java -Xms1024m -Xmx1024m -DSERVICE_LOG_FOLDER=/data/logs -jar /usr/local/software/myapp/myapp.jar --spring.config.location=/usr/local/software/myapp/bootstrap.yml
赋予文件权限
chmod +x imooc-datav.service
# 然后使用下面代码刷新后台服务
systemctl daemon-reload
启停命令
启动sshd服务:systemctl start ssh.service
停止sshd服务:systemctl stop ssh.service
查看sshd服务状态:systemctl status ssh.service
重启sshd服务:systemctl restart ssh.service
设置开机自启动:systemctl enable ssh.service
禁止开机自启动:systemctl disable ssh.service
查看所有已经启动的服务:systemctl list-units --type=service
重新加载配置文件:systemctl daemon-reload
