java?jar包后臺運行的兩種方式詳解
前言
在實際工作中,java開發(fā)的spring boot等通過jar包部署需要一直運行的程序部署到服務(wù)器上時,都希望后臺運行,方便管理程序服務(wù)、防止被誤操作關(guān)閉,本文結(jié)合自己工作經(jīng)驗講解jar包后臺運行的兩種方式,分別是按操作系統(tǒng)支持的特殊方式和統(tǒng)一執(zhí)行命令的方式。
方式一:按操作系統(tǒng)支持的方式后臺運行
可執(zhí)行jar包程序可以按操作系統(tǒng)支持的方式運行,不同操作系統(tǒng)執(zhí)行命令和方式不一樣,這里主要講解linux操作系統(tǒng)和window操作系統(tǒng)下如何按操作系統(tǒng)支持的特殊方式后臺運行。
linux操作系統(tǒng)
Linux操作系統(tǒng)java程序后臺運行又主要分如下兩種方式:
1.通過nohup命令和&符號運行。
終端關(guān)閉后程序也會繼續(xù)運行,示例如下:
nohup java -jar demo.jar > nohup.log 2>&1 &
示例命令說明:
- nohup:使得終端關(guān)閉,運行的命令也不中斷。
- java -jar demo.jar:用于啟動jar包。
- nohup.log:標(biāo)準(zhǔn)輸出重定向到nohup.log文件。
- 2>&1:標(biāo)準(zhǔn)錯誤重定向到標(biāo)準(zhǔn)輸出(即nohup.log文件)。
- &:命令放入后臺執(zhí)行。
執(zhí)行上述命令后,程序后臺運行,日志記錄到nohup.log里,可以使用tail等命令看日志文件,并且會得到一個進(jìn)程ID(PID,這個PID可以通過ps ax|grep "demo.jar"查找),可以使用kill命令通過這個PID來終止進(jìn)程。
2.jar配置為可自啟動的服務(wù)。
在Linux上將jar文件設(shè)置為服務(wù)需要編寫一個系統(tǒng)服務(wù)單元文件(.service文件),然后使用systemd來管理服務(wù)。以下是一個示例:
- 創(chuàng)建服務(wù)單元文件 ?
?/etc/systemd/system/your-service.service?
?:
[Unit] Description=Your Java Application as a Service After=network.target [Service] User=<username> Type=simple ExecStart=/usr/bin/java -jar /path/to/your-application.jar Restart=on-failure [Install] WantedBy=multi-user.target
- 重新加載systemd管理器配置:
sudo systemctl daemon-reload
- 啟動服務(wù):
sudo systemctl start your-service.service
- 設(shè)置服務(wù)開機自啟:
sudo systemctl enable your-service.service
確保替換 ??<username>?
?? 和 ??/path/to/your-application.jar?
?? 為實際的用戶名和jar文件路徑。如果需要傳遞額外的Java選項,可以在 ??ExecStart?
? 中添加。
請注意,這個示例假定你已經(jīng)有權(quán)限執(zhí)行systemctl命令,并且你的系統(tǒng)已經(jīng)安裝了Java運行時環(huán)境(JRE)或Java Development Kit(JDK)。如果沒有安裝Java,你需要先安裝它,通常可以使用系統(tǒng)的包管理器,例如在Ubuntu上使用 ??sudo apt-get install default-jdk?
?。
window操作系統(tǒng)
要在Windows環(huán)境下使jar包在后臺運行,可以使用javaw命令代替java命令,javaw命令不會打開命令行窗口,適合運行沒有圖形界面但需要在后臺運行的Java應(yīng)用程序;也可以使用??winsw?
?工具安裝為系統(tǒng)服務(wù)實現(xiàn)后臺運行。
結(jié)合操作系統(tǒng)支持的方式,window下java程序后臺運行又主要分如下四種方式:
1.使用javaw -jar demo.jar命令運行jar包
打開命令提示符或PowerShell,使用javaw -jar demo.jar命令運行jar包。
2.定時運行或開機自啟
如果需要定時運行或開機自啟,可以創(chuàng)建一個批處理文件來運行jar包,可以通過Windows任務(wù)計劃程序來設(shè)置。
示例批處理文件(run-jar.bat):
@echo off start javaw -jar demo.jar exit
3.通過VBS腳本運行
如果你想要該進(jìn)程在后臺默默運行,可以創(chuàng)建VBS腳本來啟動它:
CreateObject("Wscript.Shell").Run "cmd /c start javaw -jar your-application.jar", 0, True
保存為.vbs文件,例如run-jar.vbs,雙擊該文件即可在后臺運行jar包。
4.安裝為服務(wù)方式運行
將其作為服務(wù)安裝,可以使用??winsw?
?工具來將你的Java應(yīng)用程序包裝成Windows服務(wù)。這樣可以確保即使命令行關(guān)閉,程序也會繼續(xù)運行。
下載winsw的二進(jìn)制文件,并重命名為你的服務(wù)名稱,例如demo.exe。然后創(chuàng)建一個配置文件demo.xml,最后通過install安裝為windows服務(wù)。
安裝服務(wù)的基本步驟如下:
- 下載winsw二進(jìn)制文件。
- 重命名為demo.exe。
- 創(chuàng)建demo.xml配置文件,指定jar路徑和其他參數(shù)。
- 運行demo.exe install來安裝服務(wù)。
- 這樣,你的Java應(yīng)用程序就會作為Windows服務(wù)在后臺運行,并可以設(shè)置為開機啟動。
方式二:統(tǒng)一執(zhí)行命令的方式(Runtime.getRuntime().exec())
方式一雖然都能實現(xiàn)jar程序后臺運行但是方式并不統(tǒng)一,不同操作系統(tǒng)需要按不同方式配置,java程序既然是跨平臺的,為什么個不能讓jar包后臺運行的命令也統(tǒng)一呢?答案是肯定可以的,這兒要講的就是這種方式,實現(xiàn)也比較簡單,Vertx等項目就是按這種方式,通過java 調(diào)用系統(tǒng)命令實現(xiàn)(Runtime.getRuntime().exec())。
這種方式目標(biāo)
使用相同啟動命令使得程序可以在不同操作系統(tǒng)上后臺運行。
實現(xiàn)思路(Spring boot項目舉例)
- 程序啟動main方法傳入一個后臺運行的標(biāo)志參數(shù),比如為start。
- main方法里獲取args參數(shù)判斷是否包含start參數(shù),如果包含就獲取啟動命令和按操作系統(tǒng)設(shè)置其他啟動參數(shù),然后通過java 調(diào)用系統(tǒng)命令方式(Runtime.getRuntime().exec())再次執(zhí)行不包括start參數(shù)的啟動命令。
- 通過java 調(diào)用系統(tǒng)命令方式(Runtime.getRuntime().exec())再次執(zhí)行不包括start參數(shù)的啟動命令后,又進(jìn)入main方法,main方法args參數(shù)里沒有start參數(shù),就執(zhí)行Spring boot項目啟動代碼,這樣就實現(xiàn)了程序后臺運行。
執(zhí)行命令示例:
java -jar demo.jar start
示例代碼如下:
package com.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import java.io.File; import java.util.*; @SpringBootApplication public class DemoApplication { public static final String START = "start"; private static String osName = System.getProperty("os.name").toLowerCase(); private static String id = UUID.randomUUID().toString(); public static void main(String[] args) { HashSet<String> argSet = new HashSet<>(Arrays.asList(args)); if (argSet.contains("-Dapplication.id")||!argSet.contains(START)) { SpringApplication.run(DemoApplication.class, args); } else{ start(); } } /** * 參考io.vertx.core.impl.launcher.commands.StartCommand */ public static void start() { System.out.println("Starting application background..."); List<String> cmd = new ArrayList<>(); ProcessBuilder builder = new ProcessBuilder(); addJavaCommand(cmd); // Add the classpath to env. builder.environment().put("CLASSPATH", System.getProperty("java.class.path")); //jar包運行 if (getJar() != null) { cmd.add("-jar"); cmd.add(getJar()); } else { //開發(fā)工具運行 cmd.add(getFirstSegmentOfCommand()); cmd.add("run"); } cmd.add("-Dapplication.id=" + id); try { builder.command(cmd); builder.start(); System.out.println(id); } catch (Exception e) { System.out.println("Cannot create application process"); System.exit(12); } } private static void addJavaCommand(List<String> cmd) { if (osName.contains("windows")) { cmd.add("cmd.exe"); cmd.add("/C"); cmd.add("start"); cmd.add("application-id - " + id); cmd.add("/B"); } cmd.add(getJava().getAbsolutePath()); String opts = System.getenv("JAVA_OPTS"); if (opts != null) { cmd.addAll(Arrays.asList(opts.split(" "))); } } private static File getJava() { File java; File home = new File(System.getProperty("java.home")); if (osName.contains("windows")) { java = new File(home, "bin/java.exe"); } else { java = new File(home, "bin/java"); } if (!java.isFile()) { System.out.println("Cannot find java executable - " + java.getAbsolutePath() + " does not exist"); System.exit(14); } return java; } public static String getJar() { // Check whether or not the "sun.java.command" system property is defined, // if it is, check whether the first segment of the command ends with ".jar". String segment = getFirstSegmentOfCommand(); if (segment != null && segment.endsWith(".jar")) { return segment; } else { // Second attend is to check the classpath. If the classpath contains only one element, // it's the fat jar String classpath = System.getProperty("java.class.path"); if (!classpath.isEmpty() && !classpath.contains(File.pathSeparator) && classpath.endsWith(".jar")) { return classpath; } } return null; } /** * @return the first segment of the command line. */ public static String getFirstSegmentOfCommand() { String cmd = System.getProperty("sun.java.command"); if (cmd != null) { String[] segments = cmd.split(" "); if (segments.length >= 1) { return segments[0]; } } return null; } }
總結(jié)
到此這篇關(guān)于java jar包后臺運行兩種方式的文章就介紹到這了,更多相關(guān)java jar包后臺運行內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java正則表達(dá)式實現(xiàn)在文本中匹配查找換行符的方法【經(jīng)典實例】
這篇文章主要介紹了Java正則表達(dá)式實現(xiàn)在文本中匹配查找換行符的方法,結(jié)合具體實例分析了java正則匹配查找換行符的實現(xiàn)技巧與匹配模式相關(guān)操作注意事項,需要的朋友可以參考下2017-04-04Spring?Boot?啟動參數(shù)之如何優(yōu)雅地控制你的應(yīng)用(最新推薦)
Spring Boot 提供了哪些方式來配置這些啟動參數(shù),今天我們就來詳細(xì)解析 Spring Boot 啟動參數(shù)的各種用法,并附帶代碼示例,讓你可以靈活掌控應(yīng)用的啟動過程,需要的朋友可以參考下2025-04-04Java快速排序的實現(xiàn)詳細(xì)代碼及通俗解釋
這篇文章主要介紹了Java快速排序?qū)崿F(xiàn)的相關(guān)資料,快速排序是一種高效的排序算法,通過選擇一個基準(zhǔn)值將數(shù)組分成兩部分,左邊的元素比基準(zhǔn)值小,右邊的元素比基準(zhǔn)值大,然后遞歸地對這兩部分進(jìn)行排序,需要的朋友可以參考下2025-02-02在JPA中criteriabuilder使用or拼接多個like語句
這篇文章主要介紹了在JPA中criteriabuilder使用or拼接多個like語句,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12MYSQL批量插入數(shù)據(jù)的實現(xiàn)代碼
非常的實現(xiàn)原理,代碼較多,建議大家仔細(xì)看看。2008-10-10