Linux下啟動Springboot服務(wù)

1. 背景

由于實際項目需要,需要在 Linux 下發(fā)部署 Java Web 應(yīng)用摧阅。因為此前都是通過 Weblogic來部署的,乍換一種方式绷蹲,有點不使用棒卷。

主要遇到問題有三個:

  • 啟動過程有點繁瑣,不夠簡單易用祝钢,對維護(hù)人員有一定要求比规,去理解每個參數(shù)的設(shè)置
  • 而且啟動參數(shù),每次重啟都要輸入一堆參數(shù)拦英,不夠便捷
  • 再者蜒什,重啟過程需要找到進(jìn)程 然后 kill 掉,再重啟疤估,耗時多

2. 解決思路

通過網(wǎng)上材料灾常,無非通過 K8S 去管理部署應(yīng)用 以及 原生 Java 方式管理,但是我們的 K8S 環(huán)境還沒提供铃拇,只能暫時采用 Java 原生钞瀑。

Java 原生,參數(shù)太多慷荔,那考慮將這些參數(shù)封裝成為一個 shell 腳本雕什,以后服務(wù)的啟動、停显晶、重啟或者查看狀態(tài)贷岸,都是通過 一個 shell 腳本來完成。

Shell 腳本功能就是提供應(yīng)用的 啟動磷雇、停偿警、重啟或者查看狀態(tài)。那就是寫四個方法唯笙,分別讓用戶選擇户敬。

3. 實現(xiàn)舉措

四個核心方法,完成應(yīng)用的 啟動睁本、停尿庐、重啟或者查看狀態(tài)。

3.1. 核心方法


function start()
{

}

function stop()
{
    
}

function restart()
{
    
}

function status()
{

}


3.2. 啟動

啟動過程中指定 JVM 參數(shù)呢堰,這里提供參考 JVM_OPTS="-Dname=$SpringBoot -Duser.timezone=Asia/Shanghai -Xms1024M -Xmx1024M -XX:PermSize=256M -XX:MaxPermSize=768M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -Xloggc:$GC_LOG_PATH -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"

設(shè)置 虛擬機(jī)內(nèi)容娜汁、和 內(nèi)容異常過程中Dump操作饰抒、以及設(shè)置 GC日志路徑第步。

3.3. 停止

  • 應(yīng)用停止過程中需要判斷應(yīng)用當(dāng)前的狀態(tài)哎迄,通過 ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}' 檢查出來應(yīng)用的 PID 。

  • 通過 ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}' | xargs kill 來停止應(yīng)用

3.4. 重啟

結(jié)合 啟動和停止搪泳,查詢應(yīng)用狀態(tài),服務(wù)存在的話,則 kill 應(yīng)用贺纲,然后再啟動應(yīng)用。

3.4.1. 查看狀態(tài)

應(yīng)用停止過程中需要判斷應(yīng)用當(dāng)前的狀態(tài)褪测,通過 ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}' 檢查出來應(yīng)用的 PID 猴誊。

3.5. 其他

3.5.1. 日志路徑

默認(rèn)在當(dāng)前應(yīng)用的目錄下構(gòu)建 logs 日志文件夾,并按照應(yīng)用名稱侮措,分目錄存儲懈叹。

如應(yīng)用 A,則日志文件在 logs/A/

3.5.2. 格式化日志

利用 function log_* 方法分扎,定義日志的級別澄成。


LOG_LEVEL=1

function log_debug(){
  content="[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 1  ] && echo -e "\033[32m"  ${content}  "\033[0m"
}
function log_info(){
  content="[INFO] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 2  ] && echo -e "\033[32m"  ${content} "\033[0m"
}
function log_warn(){
  content="[WARN] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 3  ] && echo -e "\033[33m" ${content} "\033[0m"
}
function log_err(){
  content="[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 4  ] && echo -e "\033[31m" ${content} "\033[0m"
}
function log_always(){
   content="[ALWAYS] $(date '+%Y-%m-%d %H:%M:%S') $@"
   [ $LOG_LEVEL -le 5  ] && echo -e  "\033[32m" ${content} "\033[0m"
}

4. 完整文件


#!/bin/bash

# 日志級別 debug-1, info-2, warn-3, error-4, always-5
LOG_LEVEL=1

# 調(diào)試日志
function log_debug(){
  content="[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 1  ] && echo -e "\033[32m"  ${content}  "\033[0m"
}
# 信息日志
function log_info(){
  content="[INFO] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 2  ] && echo -e "\033[32m"  ${content} "\033[0m"
}
# 警告日志
function log_warn(){
  content="[WARN] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 3  ] && echo -e "\033[33m" ${content} "\033[0m"
}
# 錯誤日志
function log_err(){
  content="[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 4  ] && echo -e "\033[31m" ${content} "\033[0m"
}
# 一直都會打印的日志
function log_always(){
   content="[ALWAYS] $(date '+%Y-%m-%d %H:%M:%S') $@"
   [ $LOG_LEVEL -le 5  ] && echo -e  "\033[32m" ${content} "\033[0m"
}


SpringBoot=$1

if [ "$SpringBoot" = "" ];
then
    log_err "Please enter the Jar application name"
    lot=$(find ./ -maxdepth 1 -type f -and -name "*.jar")
    # lot_pat=${lot#*/}
    log_err "The Optional Jar applications are as follows: $lot"
    exit 1
fi

ADATE=$(date +%Y%m%d%H%M%S)

# 啟動參數(shù)
START_OPTS=$3

# JVM參數(shù)
APP_HOME=$(pwd)

dirname $0|grep "^/" >/dev/null


# 獲取當(dāng)前執(zhí)行路徑

if [ $? -eq 0 ];then
     APP_HOME=$(DIR_NAME $0)
else
     dirname $0|grep "^\." >/dev/null
     retval=$?
     if [ $retval -eq 0 ];then
        APP_HOME=$(dirname $0|sed "s#^.#$APP_HOME#")
     else
        APP_HOME=$(dirname $0|sed "s#^#$APP_HOME/#")
     fi
fi

log_info "Current directory is $APP_HOME"

ENV_PORT=${START_OPTS#*=}

ENV_DIR="$APP_HOME/logs"


if [ "$ENV_PORT" = "" ]; then
    log_info "Application Port is Null"
    log_info "$ENV_DIR"
    if [ ! -d "$ENV_DIR"  ];then
        mkdir -p $ENV_DIR
    fi

else
    log_info "Application Port is $ENV_PORT"
    ENV_DIR="$ENV_DIR/$ENV_PORT"
    log_info "$ENV_DIR"
    if [ ! -d "$ENV_DIR"  ];then
        mkdir -p $ENV_DIR
    fi
fi

log_warn " Construct log folder $ENV_DIR"

pid=0

Purpose=$2

# 當(dāng)沒有輸入具體,操作畏吓,默認(rèn)為 START 墨状,此時需要用戶二次確認(rèn),輸入 Y|y|YES|Yes 同意操作
# 或者 n|N|NO|no 菲饼,不同意重啟歉胶,直接退出
if [ "$Purpose" = "" ];
    then
        log_err "Operation Name Not Entered : The Default Action Is START !"
        read -p  "Are You Sure?[y/n]:"  sure
        case  $sure  in
            y|Y|Yes|YES)  
                log_warn "You Enter $a"
                log_warn "Prepare to restart the app: $SpringBoot"
                Purpose="start"
                ;;
            n|N|NO|no)
                echo "you enter $a"
                log_warn "Ready To Exit Startup: $SpringBoot"
                exit 1
                ;;
            *)
                echo "error";;
        esac
fi


log_debug "##############################"

log_debug "Java environment variable information"

LOG_PATH=$ENV_DIR/$SpringBoot-$ADATE.log
GC_LOG_PATH=$ENV_DIR/gc-$SpringBoot-$ADATE.log

VSpringBoot=${SpringBoot%%.*}

LOG_DEBUG_PATH=$ENV_DIR/$VSpringBoot/debug.log

log_debug "LOG_DEBUG_PATH is $LOG_DEBUG_PATH"


log_debug "$(java -version)"
log_debug "Startup log  $LOG_PATH"

log_debug "Startup gc log  $GC_LOG_PATH"

JVM_OPTS="-Dname=$SpringBoot -Duser.timezone=Asia/Shanghai -Xms1024M -Xmx1024M -XX:PermSize=256M -XX:MaxPermSize=768M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -Xloggc:$GC_LOG_PATH -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"

log_debug "$JVM_OPTS $GC_LOG_PATH"

# 啟動項目,如果項目已經(jīng)啟動過巴粪,則先 kill 掉原先項目通今,再啟動
function start()
{
    # 檢查項目的進(jìn)程是否存在
    checkPid
    # 
    if [ $pid -ne "0" ]; then
        log_info "Application  $SpringBoot Running... PID:$pid ,Please Stop It"
        # echo -e "\033[31m Application  $SpringBoot Running... PID:$pid ,Please Stop It  \033[0m"
        # Kill the current Process
        killPid
        log_info ".............."
        startFun
    else
        log_info ".............."
        startFun
        log_info ".............."
    fi
}


checkPid()
{
    pid=$(ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}')
    # `ps -aux | grep $SpringBoot | grep 'java -jar'|grep -v grep | awk '{print $2}' | xargs kill`
}

killPid()
{
    log_err "Application PID:$pid is being stopped, Please wait for a while, or fish"
    # echo -e "\033[31m Application PID:$pid is being stopped, Please wait for a while, or fish  \033[0m"
    $(ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}' | xargs kill)
    tail -n 10 $LOG_DEBUG_PATH
    sleep 10s
}

startFun()
{
    log_debug "Begin Start $SpringBoot ..."
    # echo -e "\033[32m Begin Start $SpringBoot ...  \033[0m"
    $(java -jar $JVM_OPTS $SpringBoot $START_OPTS > $LOG_PATH 2>&1 &)
    # nohup java -jar $JVM_OPTS $SpringBoot --spring.config.location=file:./application.yml $START_OPTS > $LOG_PATH 2>&1 &
    log_debug "$SpringBoot SUCCESS..."
    #echo -e "\033[32m $SpringBoot SUCCESS...  \033[0m"
    sleep 10s
    tail -n 300 $LOG_PATH

}

function stop()
{
    checkPid
    log_info "Begin Stop Application $SpringBoot"
    # echo "Begin Stop Application $SpringBoot"
    if [ "$pid" -ne "0" ]; then
        log_err "$SpringBoot stop..."
        # echo "$SpringBoot stop..."
        killPid
    else
        log_info "$SpringBoot not running!"
        # echo "$SpringBoot not running!"
    fi

}

function restart()
{
    # stop
    sleep 3s
    start
}

function status()
{
    checkPid
    if [ "$pid" -ne "0" ]; then
        log_info "$SpringBoot not running!"
        #echo "$SpringBoot not running!"    
    else
        log_info "$SpringBoot is running... PID:$pid"
        # echo "$SpringBoot is running... PID:$pid"
    fi
}

case $Purpose in
    start) start;;
    stop) stop;;
    restart) restart;;
    status) status;;
    *) log_info "require start|stop|restart|status"  ;;

esac


5. 使用

sh restart.sh $1 $2 $3

  • $1 : SpringBoot 應(yīng)用名.jar 必選
  • $2 :操作內(nèi)容,可空肛根,為空默認(rèn)為 restart
  • $3 : 其他參數(shù)辫塌,可空

樣例如下:


sh restart.sh cia-codegen.jar

6. 效果圖

20220720165706.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市派哲,隨后出現(xiàn)的幾起案子臼氨,更是在濱河造成了極大的恐慌,老刑警劉巖芭届,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件储矩,死亡現(xiàn)場離奇詭異,居然都是意外死亡褂乍,警方通過查閱死者的電腦和手機(jī)持隧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逃片,“玉大人屡拨,你說我怎么就攤上這事。” “怎么了呀狼?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵裂允,是天一觀的道長。 經(jīng)常有香客問我哥艇,道長绝编,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任貌踏,我火速辦了婚禮十饥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哩俭。我一直安慰自己,他們只是感情好拳恋,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布凡资。 她就那樣靜靜地躺著,像睡著了一般谬运。 火紅的嫁衣襯著肌膚如雪隙赁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天梆暖,我揣著相機(jī)與錄音伞访,去河邊找鬼。 笑死轰驳,一個胖子當(dāng)著我的面吹牛厚掷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播级解,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼冒黑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了勤哗?” 一聲冷哼從身側(cè)響起抡爹,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎芒划,沒想到半個月后冬竟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡民逼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年泵殴,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拼苍。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡袋狞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苟鸯,我是刑警寧澤同蜻,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站早处,受9級特大地震影響湾蔓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜砌梆,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一默责、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咸包,春花似錦桃序、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至坟比,卻和暖如春芦鳍,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背葛账。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工柠衅, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人籍琳。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓菲宴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親趋急。 傳聞我的和親對象是個殘疾皇子裙顽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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