首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 項目部署腳本最佳實踐:啟動、停止、Dump 一鍵自動化

     編輯:Java 綜合教學

Java 項目部署腳本最佳實踐:啟動、停止、Dump 一鍵自動化

從「手動啟動 Jar」到「一鍵部署運維」,一套成熟的 Shell 腳本能解決 90% 的發布痛點。本文提供基於 Spring Boot 的生產級部署腳本三件套:start.sh、stop.sh、dump.sh,並詳細解析關鍵邏輯。

一、標準目錄結構

project-root/
├── bin/                 # 腳本目錄
│   ├── start.sh
│   ├── stop.sh
│   └── dump.sh
├── lib/                 # 依賴 JAR 包
├── conf/                # 配置文件
├── logs/                # 日志輸出(運行時創建)
├── dump/                # 診斷快照(運行時創建)
└── app.jar              # 業務主 JAR (Spring Boot Fat Jar)

Maven 打包插件配置:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <layout>ZIP</layout>  <!-- 或 JAR -->
        <includes>
            <include>
                <groupId>nothing</groupId>
                <artifactId>scripts</artifactId>
            </include>
        </includes>
    </configuration>
</plugin>

二、start.sh - 智能啟動腳本

#!/bin/bash
# version: 1.0.0

cd `dirname $0`          # 進入腳本所在目錄 (bin/)
BIN_DIR=`pwd`
cd ..                    # 返回項目根目錄
DEPLOY_DIR=`pwd`

SERVER_NAME=`basename $DEPLOY_DIR`      # 以根目錄名作為服務名
CONF_DIR=$DEPLOY_DIR/conf
LIB_DIR=$DEPLOY_DIR/lib
LOGS_DIR=$DEPLOY_DIR/logs
STDOUT_FILE=$LOGS_DIR/stdout.log

# 1. 防重複啟動
PIDS=`ps -ef | grep java | grep "$CONF_DIR" | awk '{print $2}'`
if [ -n "$PIDS" ]; then
    echo "ERROR: The $SERVER_NAME already started! PID: $PIDS"
    exit 1
fi

# 2. 準備日志目錄
mkdir -p $LOGS_DIR

# 3. 構建 Classpath
LIB_JARS=`ls $LIB_DIR | grep .jar | awk '{print "'$LIB_DIR'/"$0}' | tr "\n" ":"`
MAIN_JAR=`ls $DEPLOY_DIR | grep .jar | awk '{print "'$DEPLOY_DIR'/"$0}' | tr "\n" ":"`
CLASSPATH="$CONF_DIR:$LIB_JARS:$MAIN_JAR"

# 4. JVM 參數(根據架構自動調整)
JAVA_OPTS=" -Djava.net.preferIPv4Stack=true -Dlog.home=$LOGS_DIR"
BITS=`java -version 2>&1 | grep -i 64-bit`
if [ -n "$BITS" ]; then
    JAVA_MEM_OPTS=" -server -Xms2g -Xmx2g -XX:PermSize=128m -XX:MaxPermSize=128m \
        -XX:SurvivorRatio=6 -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled \
        -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=80 \
        -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark \
        -XX:+PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails \
        -Xloggc:gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 \
        -XX:GCLogFileSize=100M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=dump.hprof"
else
    JAVA_MEM_OPTS=" -server -Xms1g -Xmx1g -XX:PermSize=128m -XX:MaxPermSize=128m \
        -XX:SurvivorRatio=2 -XX:+UseParallelGC"
fi

# 5. 啟動應用
echo -e "Starting the $SERVER_NAME ...\c"
nohup java $JAVA_OPTS $JAVA_MEM_OPTS -classpath $CLASSPATH \
    com.example.Application > $STDOUT_FILE 2>&1 &

# 6. 健康檢查等待
COUNT=0
while [ $COUNT -lt 1 ]; do
    echo -e ".\c"
    sleep 1
    COUNT=`ps -f | grep java | grep "$DEPLOY_DIR" | awk '{print $2}' | wc -l`
    if [ $COUNT -gt 0 ]; then break; fi
done

echo "OK!"
PIDS=`ps -f | grep java | grep "$DEPLOY_DIR" | awk '{print $2}'`
echo "PID: $PIDS"
echo "STDOUT: $STDOUT_FILE"

關鍵點解析

  • dirname $0 + cd ..:動態定位項目根目錄,支持任意路徑調用
  • grep "$CONF_DIR":精準匹配進程,避免誤殺同機其他 Java 進程
  • Classpath 動態拼接:conf:lib/*:app.jar,無需修改 Manifest
  • 64/32 位 JVM 參數自適應:CMS vs ParallelGC
  • GC 日志輪轉:防止磁盤寫滿
  • nohup ... &:後台守護進程模式

三、stop.sh - 優雅停止腳本

#!/bin/bash
cd `dirname $0`; BIN_DIR=`pwd`; cd ..; DEPLOY_DIR=`pwd`
CONF_DIR=$DEPLOY_DIR/conf
SERVER_NAME=`basename $DEPLOY_DIR`

PIDS=`ps -ef | grep java | grep "$CONF_DIR" | awk '{print $2}'`
if [ -z "$PIDS" ]; then
    echo "ERROR: The $SERVER_NAME does not started!"
    exit 1
fi

# 支持 dump 參數:停止前導出診斷信息
if [ "$1" == "dump" ]; then
    $BIN_DIR/dump.sh
fi

echo -e "Stopping the $SERVER_NAME ...\c"
for PID in $PIDS; do
    kill $PID > /dev/null 2>&1      # 先發 SIGTERM (15),給 Spring 關閉鉤子執行時間
done

# 等待進程退出
COUNT=0
while [ $COUNT -lt 1 ]; do
    echo -e ".\c"
    sleep 1
    COUNT=1
    for PID in $PIDS; do
        PID_EXIST=`ps -f -p $PID | grep java`
        if [ -n "$PID_EXIST" ]; then COUNT=0; break; fi
    done
done

echo "OK!"
echo "PID: $PIDS"

優雅停止要點

  • kill $PID 發送 SIGTERM (15),非 SIGKILL (9),讓 Spring 執行 @PreDestroy、關閉線程池、釋放鎖
  • 輪詢確認進程退出,避免殭屍進程
  • 支持 ./stop.sh dump 一鍵「先診斷後停止」

四、dump.sh - 線上診斷快照腳本

#!/bin/bash
cd `dirname $0`; BIN_DIR=`pwd`; cd ..; DEPLOY_DIR=`pwd`
CONF_DIR=$DEPLOY_DIR/conf
SERVER_NAME=`basename $DEPLOY_DIR`

PIDS=`ps -ef | grep java | grep "$CONF_DIR" | awk '{print $2}'`
if [ -z "$PIDS" ]; then
    echo "ERROR: The $SERVER_NAME does not started!"
    exit 1
fi

LOGS_DIR=$DEPLOY_DIR/logs
DUMP_DIR=$LOGS_DIR/dump
DUMP_DATE=`date +%Y%m%d%H%M%S`
DATE_DIR=$DUMP_DIR/$DUMP_DATE
mkdir -p $DATE_DIR

echo -e "Dumping the $SERVER_NAME ...\c"
for PID in $PIDS; do
    jstack $PID > $DATE_DIR/jstack-$PID.dump 2>&1; echo -e ".\c"
    jinfo $PID > $DATE_DIR/jinfo-$PID.dump 2>&1; echo -e ".\c"
    jstat -gcutil $PID > $DATE_DIR/jstat-gcutil-$PID.dump 2>&1; echo -e ".\c"
    jstat -gccapacity $PID > $DATE_DIR/jstat-gccapacity-$PID.dump 2>&1; echo -e ".\c"
    jmap $PID > $DATE_DIR/jmap-$PID.dump 2>&1; echo -e ".\c"
    jmap -heap $PID > $DATE_DIR/jmap-heap-$PID.dump 2>&1; echo -e ".\c"
    jmap -histo $PID > $DATE_DIR/jmap-histo-$PID.dump 2>&1; echo -e ".\c"
    if [ -r /usr/sbin/lsof ]; then
        /usr/sbin/lsof -p $PID > $DATE_DIR/lsof-$PID.dump; echo -e ".\c"
    fi
done

# 系統級快照
for cmd in netstat iostat mpstat vmstat free sar uptime; do
    if [ -r /usr/bin/$cmd ] || [ -r /bin/$cmd ]; then
        $cmd > $DATE_DIR/$cmd.dump 2>&1; echo -e ".\c"
    fi
done

echo "OK!"
echo "DUMP: $DATE_DIR"

Dump 包含內容

工具輸出文件診斷價值
jstackjstack-PID.dump線程堆棧,定位死鎖、CPU 高、線程阻塞
jinfojinfo-PID.dumpJVM 參數、系統屬性、命令行參數
jstat -gcutiljstat-gcutil-PID.dumpGC 統計:Eden/Survivor/Old 使用率、GC 次數/耗時
jstat -gccapacityjstat-gccapacity-PID.dump各代容量大小、最大值
jmapjmap-PID.dump堆內存映射、類加載統計
jmap -heapjmap-heap-PID.dump堆配置詳情、GC 算法、各區大小
jmap -histojmap-histo-PID.dump對象統計:實例數、大小、類名(找內存洩漏)
lsoflsof-PID.dump進程打開文件、網絡連接
netstat/iostat/...系統級.dump網絡、磁盤 I/O、CPU、內存、負載

五、使用建議

  1. 腳本放在 src/main/scripts,Maven 打包自動拷貝到 bin/
  2. 賦予執行權限:chmod +x bin/*.sh
  3. 啟動:./bin/start.sh | 停止:./bin/stop.sh | 診斷:./bin/dump.sh | 停止前診斷:./bin/stop.sh dump
  4. 日志查看:tail -f logs/stdout.log 或 tail -f logs/gc.log
  5. 定期清理 logs/ 和 dump/ 歷史文件

這套腳本經過多個生產項目驗證,支撐了從啟動、運行、故障診斷到優雅下線的完整生命週期管理。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved