記一次Java程序自我重啟的功能實現(xiàn)

身為一名coder赴穗,世界上最幸福的事莫過于開發(fā)別人沒開發(fā)出的功能炕吸;最近接到了一個需求,需要通過web頁面下達重啟命令利耍,后臺程序讀取到這個命令能夠實現(xiàn)自我重啟蚌本;

當時我們公司已經有其他項目實現(xiàn)了這個功能,是不過是通過另一個類似看門狗的程序來控制主程序的啟停操作隘梨,不過程癌。。轴猎。項目經理說我們最好能夠在主程序內部實現(xiàn)嵌莉,現(xiàn)場要是再部署另一個程序會很麻煩,呃(⊙﹏⊙)捻脖,好吧锐峭,頭腦風暴了一會兒之后心想這還不簡單?大概分為如下幾步:

1可婶、數據庫建一個任務表用于記錄啟停操作

2沿癞、寫一個定時任務用于讀取該任務表的標記位,每20秒執(zhí)行一次

3矛渴、web頁面點擊“重啟”操作之后修改任務標記位

4椎扬、定時任務監(jiān)控到標記位變化之后通過Java執(zhí)行重啟的shell腳本

列出了如上思路后開始實現(xiàn)。具温。蚕涤。。铣猩。

RuntimeUtils.java(用于執(zhí)行sh或bat腳本的工具類)

/**
 * 執(zhí)行sh或bat腳本的工具類
*/
public class RuntimeUtils {
    
    /**  
     *   
    * @Title: exec
    * @Description: 簡化執(zhí)行命令行
    * @param  command 命令行
    * @param  envp 環(huán)境變量
    * @param  dir  路徑
    * @return Process    返回類型
    * @throws IOException
     */
    public static Process exec(String command, String envp, String dir)
            throws IOException {
        String regex = "\\s+";
        String args[] = null;
        String envps[] = null;
        if (command != null && command.length() != 0) {
            args = command.split(regex);
        }
        if (envp != null && envp.length() != 0) {
            envps = envp.split(regex);
        }
        return Runtime.getRuntime().exec(args, envps, new File(dir));
    }
}

LinuxShell.java(新建一個類用于專門封裝一些linux操作)

/**
 * Linux命令操作
*/
public class LinuxShell {
    
    public static void restartCalc() throws Exception{
        String command = "sh *** restart";  //***是程序名揖铜,sh后面就是要執(zhí)行的命令
        String dir = VoltConfig.restartFilePath;
        Process process = RuntimeUtils.exec(command, null, dir);
        int i = process.waitFor();
        System.exit(i);
    }

}

web部分的代碼就不貼了。达皿。
寫完如上代碼之后天吓,后面在定時任務里調用,調用方式如下(由于部分代碼涉及到公司私密設計峦椰,就不貼出來了):

//判斷是否需要重啟
if(heartBeat.getRebootFlag().equals("0")) {
    //執(zhí)行重啟腳本
    if(VoltConfig.rebootType.equals("sh")) {
        logger.info("監(jiān)測到重啟命令失仁,開始重啟...");
        LinuxShell.restartCalc();
    }
    //TODO 待擴展,windows下執(zhí)行bat腳本
} else {
    logger.info("未監(jiān)測到重啟命令");
}

開開心心的寫完后發(fā)現(xiàn)整個難度也就那樣们何,后面就是打包驗證了

打包到部署到啟動一切都很順利,下面就是結合web來實現(xiàn)指令控制了

web頁面下達重啟命令后控轿,我預計的效果并沒有達到冤竹,日志如下:


程序部分日志

怎么只停止了拂封?為什么沒有啟動?

反復查看了那幾行代碼鹦蠕,盲猜程序執(zhí)行l(wèi)inux命令的方法是異步的冒签,腳本還沒執(zhí)行完程序就停止了

于是把System.exit(i);這一句刪掉,下面重啟打包測試钟病。萧恕。。肠阱。

還是不行票唆!還是跟之前一樣的效果,程序依然只是停止屹徘,沒有執(zhí)行啟動操作走趋,為什么?
非要我面向百度編程噪伊?

百度了一下發(fā)現(xiàn)別人也有這種需求簿煌,,鉴吹,好吧姨伟,是我自作多情了,看了一下基本就是程序自我重啟本身這條思路就不可行6估6峄摹!肆糕!都是通過另一個程序來控制主程序的啟停般堆!WTF?诚啃?淮摔?

不甘心的我反復思考了為什么,總結了以下可能的情況(百度找不到原因始赎,只能自我主觀地總結和橙,希望看到本篇文章的大佬指點一二):

程序從開始執(zhí)行l(wèi)inux命令,一直到linux命令執(zhí)行結束都是在JVM里執(zhí)行造垛,并不是理想中的程序只負責調用一下shell腳本魔招,剩下的交由shell腳本去自己完成執(zhí)行。
當JVM執(zhí)行重啟命令執(zhí)行到程序停止時五辽,此時JVM已經被銷毀办斑,接下來的步驟沒有程序去執(zhí)行了,所以腳本里剩下的啟動操作就沒執(zhí)行

總結上面原因后,大概這條路就行不通了乡翅,還是得想別的辦法

反觀當前狀況并不是一無所獲鳞疲,起碼我收到命令能夠自我停止( ̄??)

后面就需要一個監(jiān)控程序來監(jiān)控程序的運行狀態(tài),當程序處于停止狀態(tài)時蠕蚜,自動執(zhí)行啟動操作尚洽,可是說好不再寫輔助程序的。靶累。腺毫。

不寫Java,我們可以通過shell腳本來實現(xiàn)對程序運行狀態(tài)的監(jiān)控

順了一下監(jiān)控程序的實現(xiàn)思路大概就是:
1挣柬、查看當前程序的在運進程個數
2潮酒、如果進程數為0,說明程序處于停止狀態(tài)凛忿,此時執(zhí)行啟動命令
3澈灼、如果進程數大于0,說明程序在運狀態(tài)
4店溢、上面步驟需要定時循環(huán)

shell腳本如下:

#!/bin/bash
date=`date +%Y-%m-%d_%H:%M:%S`
##監(jiān)控腳本日志存放路徑
recorddir=/home/voltCalc/Test/logs
##監(jiān)控腳本日志文件名稱
recordfile=listener.`date +%Y-%m-%d`.log
##Test啟動文件所在路徑
Testurl=/home/Test
##normal--正常運行;upgrade--升級
usefor=normal
monitor()  
{   
    if [ ! -d ${recorddir} ] ; then
        mkdir -p ${recorddir}
    fi
     
    if [ "${usefor}" == "normal" ] ; then
        ##Test的進程數,由于腳本名稱為Test.sh叁熔,所以排除了對Test的搜索
        count=`ps -ef|grep Test|grep -v "grep"|grep -v "Test.log"|wc -l`
        if [ ${count} -gt 0 ] ; then
            echo "${date},Test服務運行正常!"
        else
            sh ${Testurl}/run.sh
            echo "${date},重啟了Test服務床牧!"
        fi
    elif [ "${usefor}" == "upgrade" ] ; then
        echo "${date},系統(tǒng)升級荣回,不需要重新啟動Test服務!"
    else
        echo "${date},參數配置異常,請檢查usefor參數戈咳!"
    fi
}  

for (( i=1; i>0; i=1)); do
  monitor >> ${recorddir}/${recordfile}
  sleep 5
done

exit 0

于是乎心软,程序不用變,當頁面下達重啟命令后
程序停止著蛙,監(jiān)控腳本監(jiān)控到停止狀態(tài)執(zhí)行啟動操作
需求完成删铃!

就是升級的時候需要多一個shell腳本了,emm....

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末踏堡,一起剝皮案震驚了整個濱河市猎唁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌顷蟆,老刑警劉巖诫隅,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異帐偎,居然都是意外死亡逐纬,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門削樊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來豁生,“玉大人,你說我怎么就攤上這事∨婀瑁” “怎么了眼刃?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長摇肌。 經常有香客問我,道長仪际,這世上最難降的妖魔是什么围小? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮树碱,結果婚禮上肯适,老公的妹妹穿的比我還像新娘。我一直安慰自己成榜,他們只是感情好框舔,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赎婚,像睡著了一般刘绣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挣输,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天纬凤,我揣著相機與錄音,去河邊找鬼撩嚼。 笑死停士,一個胖子當著我的面吹牛,可吹牛的內容都是我干的完丽。 我是一名探鬼主播恋技,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼逻族!你這毒婦竟也來了蜻底?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤瓷耙,失蹤者是張志新(化名)和其女友劉穎朱躺,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體搁痛,經...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡长搀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了鸡典。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片源请。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出谁尸,到底是詐尸還是另有隱情舅踪,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布良蛮,位于F島的核電站抽碌,受9級特大地震影響,放射性物質發(fā)生泄漏决瞳。R本人自食惡果不足惜货徙,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望皮胡。 院中可真熱鬧痴颊,春花似錦、人聲如沸屡贺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽甩栈。三九已至泻仙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谤职,已是汗流浹背饰豺。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留允蜈,地道東北人冤吨。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像饶套,于是被迫代替她去往敵國和親漩蟆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355