運行 Java SpringBoot 的 Linux 腳本 run.sh

一個用于運行 Java SpringBoot 的 Linux 腳本 run.sh

  1. 自動根據(jù)所在目錄獲取最新的可執(zhí)行 jar盟迟、war
  2. 自動使用環(huán)境變量 JAVA_HOME 進行執(zhí)行命令(可配置)
  3. 支持優(yōu)雅下線(默認等待60秒秋泳,可配置,如果超過60秒則強制下線)
  4. 支持監(jiān)聽 SpringBoot 上線狀態(tài)
  5. 支持添加自定義運行參數(shù)(如:JVM 參數(shù)攒菠、SpringBoot 參數(shù))
  6. 支持常用功能:啟動迫皱、停止、重啟辖众、查看狀態(tài)卓起、查看日志
  7. SpringBoot 項目支持查看應用端口信息

目錄結(jié)構(gòu)如下

├── fastboot-0.0.1.jar                      # 應用jar
├── logs
│   ├── console.log                         # 應用控制臺輸入的日志
│   └── server.pid                          # 應用的pid
└── run.sh                                  # 執(zhí)行腳本

可配置的參數(shù)

1. 用法

添加文件的執(zhí)行權(quán)限

# 首次執(zhí)行第一次即可
chmod +x run.sh

重啟并清空日志

查看狀態(tài)

啟動

停止

2. 說明

# 賦予執(zhí)行權(quán)限(初始化執(zhí)行一次)
chmod +x run.sh 
# 啟動應用程序
sh run.sh start
# 停止應用程序
sh run.sh stop
# 查看應用程序
# sh run.sh status
# 重啟應用程序
sh run.sh restart c  # 加 c 刪除歷史日志文件
# 查看應用日志
sh run.sh logs

3. 源碼(run.sh)

#!/bin/bash
#
# ================================================ 說明 start ================================================
# 1. 賦予執(zhí)行權(quán)限: chmod +x run.sh
# 2. 啟動應用程序: sh run.sh start
# 3. 停止應用程序: sh run.sh stop
# 4. 查看應用程序: sh run.sh status
# 5. 重啟應用程序: sh run.sh restart c # 加 c 刪除歷史日志文件
# 6. 查看應用日志: sh run.sh logs
# ================================================ 說明 end   ================================================
#
# ================================================ 作者 start ================================================
# @author: houyu
# @date: 2021-08-19
# @mail: for.houyu@qq.com(272694308@qq.com)
# @blog: https://www.ihouyu.cn
# @csdn: https://blog.csdn.net/JinglongSource
# ================================================ 作者 end   ================================================
# 刷新環(huán)境變量
source /etc/profile
# ================================================ 參數(shù) start ================================================
# ------ Java 路徑, 可以是 JAVA_HOME 也可以 Java 可執(zhí)行文件路徑, 默認使用環(huán)境變量的 JAVA_HOME
#JAVA="/usr/local/java/jdk1.8.0_281/bin/java"
#JAVA="/usr/local/java/jdk1.8.0_281"
JAVA="${JAVA_HOME}"
# ------ 文件路徑
DIR_PATH=`cd $(dirname $0); pwd`
# ------ 服務文件名(默認使用目錄下最新的.jar或者.war文件)
SERVER_FILE_NAME=`ls -t ${DIR_PATH} | egrep '\.jar|\.war' | head -1`
# ------ Java 參數(shù)
JAVA_OPT="${JAVA_OPT} -Duser.timezone=Asia/Shanghai"
JAVA_OPT="${JAVA_OPT} -Xms128m -Xmx128m"
# ------ Spring 參數(shù)
SPRING_OPT="${SPRING_OPT} --spring.profiles.active=prod"
# ------ 控制臺文件
#CONSOLE_FILE="/dev/null"
CONSOLE_FILE="${DIR_PATH}/logs/console.log"
# ------ 停止時等待超時的秒數(shù)
STOP_TIMEOUT=60
#
# ================================================ 參數(shù) end   ================================================
#
# ================================================ 方法 start ================================================
#
# 服務PID
_SERVER_PID=0
# 服務端口
_SERVER_PORT=0
# 日志目錄
_LOG_PATH="${DIR_PATH}/logs"
# 輸入的第二個參數(shù)
_P2=$2
#
# =======================================
# 解析服務的 pid
# =======================================
resolve_server_pid() {
    _SERVER_PID=0
    if [ -f "${_LOG_PATH}/server.pid" ]; then
        # pid 文件存在則讀取文件
        _SERVER_PID=$(cat "${_LOG_PATH}/server.pid")
        # 判斷是否真的存在這個 pid
        if test $(ps -ef | awk '{print $2}' | grep -w ${_SERVER_PID} | wc -l) -eq 0; then
            # 沒有找到文件記錄的 pid, 刪除這個文件
            rm -rf ${_LOG_PATH}/server.pid
            sleep 0.2
            _SERVER_PID=0
            # 重新解析服務的 pid
            #resolve_server_pid
        fi
    #else
    #    # pid文件不存在則嘗試根據(jù)應用程序的名稱獲取pid
    #    if test $(pgrep -f ${SERVER_FILE_NAME} | wc -l) -gt 0; then
    #        # 說明應用程序正在跑, 使用第一個pid
    #        _SERVER_PID=$(pgrep -f ${SERVER_FILE_NAME} | head -1)
    #    else
    #        _SERVER_PID=0
    #    fi
    fi
}
#
# =======================================
# 解析服務的端口
# =======================================
retry_resolve_server_port() {
    _SERVER_PORT=0
    # 解析服務的 pid
    resolve_server_pid
    # 檢測5分鐘(300秒)
    for(( i=0; i<=300; i++ )); do
        # 判斷 pid 是否存在
        if test $(ps -ef | awk '{print $2}' | grep -w ${_SERVER_PID} | wc -l) -eq 0; then
            rm -rf ${_LOG_PATH}/server.pid
            _SERVER_PID=0
            break
        fi
        # 判斷 pid 的 port 是否綁定
        if test $(netstat -tulnp | grep "${_SERVER_PID}/" | wc -l) -gt 0; then
            _SERVER_PORT=$(netstat -tulnp | grep "${_SERVER_PID}/" | head -1 | awk '{print $4}' | awk -F ":" '{print $NF}')
            break
        fi
        [[ $i%5 -eq 0 ]] && echo "--- Observing server port using ${i}s"
        sleep 1
    done
}
#
# =======================================
# 啟動
# =======================================
start() {
    echo "----------------------------------------------------------------------------- Start [0] ------"
    # 解析服務的 pid
    resolve_server_pid
    if [ "${_SERVER_PID}" -ne 0 ]; then
        # 如果 _SERVER_PID != 0, 那就說明應用程序在運行,不進行啟動
        echo "--- Do not start, ${SERVER_FILE_NAME} already started! [ SERVER_PID = ${_SERVER_PID} ]"
        echo "----------------------------------------------------------------------------- Start [1] ------"
        return
    fi
    #
    echo "--- Starting ${SERVER_FILE_NAME} ..."
    # 如果 JAVA 是一個目錄,則加上/bin/java
    [ -d "${JAVA}" ] && JAVA="${JAVA}/bin/java"
    # 如果 JAVA 不是一個存在的文件, 則嘗試使用默認的java
    [ ! -e "$JAVA" ] && JAVA=`which java`
    # 最終 Java 不是一個存在的文件, 則清空
    [ ! -e "$JAVA" ] && unset JAVA
    if [ -z "${JAVA}" ]; then
        echo -e "\033[31mPlease set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better!\033[0m"
        exit 1
    fi
    # 判斷是否需要刪除日志文件
    if [[ "$_P2" == "c" ]]; then
        # 如果第二個參數(shù)是c, 刪除日志文件
        echo -e "--- \033[33mDeleting ${SERVER_FILE_NAME} log file(${DIR_PATH}/logs/*)\033[0m"
        rm -rf ${DIR_PATH}/logs/*
    fi
    # 檢查日志目錄
    test -d ${DIR_PATH}/logs/ || mkdir -p ${DIR_PATH}/logs/
    # 執(zhí)行腳本
    # nohup java -Xmx128m -jar /home/app/server.jar --spring.profiles.active=prod >> /home/app/logs/console.log 2>&1 & echo $! > /home/app/logs/server.pid
    #
    # 運行的參數(shù)
    RUN_OPT="${JAVA_OPT} -jar"
    RUN_OPT="${RUN_OPT} ${DIR_PATH}/${SERVER_FILE_NAME}"
    [ -n "${SPRING_OPT}" ] && RUN_OPT="${RUN_OPT} ${SPRING_OPT}"
    #
    echo "--- $JAVA ${RUN_OPT}"
    echo "$JAVA ${RUN_OPT}" > ${CONSOLE_FILE}
    nohup $JAVA ${RUN_OPT} >> ${CONSOLE_FILE} 2>&1 & echo $! > ${_LOG_PATH}/server.pid
    #
    echo "--- ${SERVER_FILE_NAME} is running"
    echo -e "--- You can check the log file \033[36m${CONSOLE_FILE}\033[0m or execute the command on the next line"
    echo -e "--- \033[40;37mtail -f -n 300 ${CONSOLE_FILE}\033[0m"
    # 睡眠1秒
    sleep 1
    # 解析服務的 pid
    resolve_server_pid
    # 判斷應用程序是否成功跑起來
    if [ "${_SERVER_PID}" -eq 0 ]; then
        echo -e "--- \033[31mStart failure ${SERVER_FILE_NAME}\033[0m"
    else
        if [ -n "${SPRING_OPT}" ]; then
            # 如果是 Spring 項目, 需要觀察端口是否成功綁定
            retry_resolve_server_port
            # 
            if [ "${_SERVER_PORT}" -eq 0 ]; then
                echo -e "--- \033[31mStart failure ${SERVER_FILE_NAME}\033[0m"
            else
                _SERVER_PORT_TEXT=`netstat -tulnp | grep "${_SERVER_PID}/" | awk 'BEGIN{ORS=" "}{print $4}'`
                echo -e "--- \033[32mStart successfully ${SERVER_FILE_NAME} [ SERVER_PID = ${_SERVER_PID}, SERVER_PORT = ${_SERVER_PORT_TEXT}]\033[0m"
            fi
        else
            echo -e "--- \033[32mStart successfully ${SERVER_FILE_NAME} [ SERVER_PID = ${_SERVER_PID}, \033[0m\033[33mSERVER_PORT = unknown \033[0m\033[32m]\033[0m"
        fi
    fi
    echo "----------------------------------------------------------------------------- Start [1] ------"
}
#
# =======================================
# 停止
# =======================================
stop() {
    echo "----------------------------------------------------------------------------- Stop  [0] ------"
    # 解析服務的 pid
    resolve_server_pid
    if [ "${_SERVER_PID}" -eq 0 ]; then
        # _SERVER_PID = 0, 那就說明應用程序沒有在運行
        echo "--- Stopped ${SERVER_FILE_NAME}"
        echo "----------------------------------------------------------------------------- Stop  [1] ------"
        return
    fi
    echo "--- Graceful Stopping ${SERVER_FILE_NAME} ..."
    # 進行優(yōu)雅停機
    kill -15 ${_SERVER_PID}
    # 當前等待秒數(shù)
    _wait_seconds=0
    #
    while true; do
        if test $(ps -ef | awk '{print $2}' | grep -w ${_SERVER_PID} | wc -l) -eq 0; then
            echo "--- Stopped ${SERVER_FILE_NAME}"
            break
        fi
        if [ "${_wait_seconds}" -ge "${STOP_TIMEOUT}" ]; then
            # 強制終止進程
            echo -e "--- \033[31mWait timeout(${_wait_seconds}s), forced shutdown [kill -9 ${SERVER_FILE_NAME}].\033[0m"
            sudo kill -9 ${_SERVER_PID}
            break
        fi
        sleep 1
        let _wait_seconds++
        echo "--- Wait ${_wait_seconds}s"
    done
    if [ $? -eq 0 ]; then
        echo "--- Stop successfully ${SERVER_FILE_NAME}"
        rm -rf ${_LOG_PATH}/server.pid
    else
        echo "--- Stop failure ${SERVER_FILE_NAME}"
    fi
    echo "----------------------------------------------------------------------------- Stop  [1] ------"
}
#
# =======================================
# 狀態(tài)
# =======================================
status() {
    echo "----------------------------------------------------------------------------- status [0] ------"
    # 解析服務的 pid
    resolve_server_pid
    if [ "${_SERVER_PID}" -eq 0 ]; then
        echo -e "--- \033[33mStopped $SERVER_FILE_NAME\033[0m"
    else
        _SERVER_PORT_TEXT=`netstat -tulnp | grep "${_SERVER_PID}/" | awk 'BEGIN{ORS=" "}{print $4}'`
        [ -z "$_SERVER_PORT_TEXT" ] && _SERVER_PORT_TEXT="unknown "
        echo -e "--- \033[32mRunning ${SERVER_FILE_NAME} [ SERVER_PID = ${_SERVER_PID}, SERVER_PORT = ${_SERVER_PORT_TEXT}]\033[0m"
        echo -e "--- You can check the log file \033[36m${CONSOLE_FILE}\033[0m or execute the command on the next line"
        echo -e "--- \033[40;37mtail -f -n 300 ${CONSOLE_FILE}\033[0m"
    fi
    echo "----------------------------------------------------------------------------- status [1] ------"
}
#
# =======================================
# 日志
# =======================================
logs() {
    tail -f -n 3000 ${CONSOLE_FILE}
}
#
# ================================================ 方法 end   ================================================
#
case "$1" in
'start')
    start
    ;;
'stop')
    stop
    ;;
'restart')
    stop
    start
    ;;
'status')
    status
    ;;
'logs')
    logs
    ;;
*)
    echo "requires parameter [start|stop|restart|status|logs] [c]?"
    exit 1
    ;;
esac
#
#
#

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市凹炸,隨后出現(xiàn)的幾起案子戏阅,更是在濱河造成了極大的恐慌,老刑警劉巖还惠,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饲握,死亡現(xiàn)場離奇詭異私杜,居然都是意外死亡蚕键,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門睁壁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來难衰,“玉大人憋活,你說我怎么就攤上這事√艿” “怎么了蹬刷?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長频丘。 經(jīng)常有香客問我办成,道長,這世上最難降的妖魔是什么搂漠? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任迂卢,我火速辦了婚禮,結(jié)果婚禮上桐汤,老公的妹妹穿的比我還像新娘而克。我一直安慰自己,他們只是感情好怔毛,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布员萍。 她就那樣靜靜地躺著,像睡著了一般拣度。 火紅的嫁衣襯著肌膚如雪碎绎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天抗果,我揣著相機與錄音混卵,去河邊找鬼。 笑死窖张,一個胖子當著我的面吹牛幕随,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宿接,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼赘淮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了睦霎?” 一聲冷哼從身側(cè)響起梢卸,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎副女,沒想到半個月后蛤高,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡碑幅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年戴陡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片沟涨。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡恤批,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出裹赴,到底是詐尸還是另有隱情喜庞,我是刑警寧澤诀浪,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站延都,受9級特大地震影響雷猪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晰房,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一春宣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嫉你,春花似錦月帝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至距误,卻和暖如春簸搞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背准潭。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工趁俊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刑然。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓寺擂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親泼掠。 傳聞我的和親對象是個殘疾皇子怔软,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容