java?jar包后臺運(yùn)行的兩種方式詳解
前言
在實(shí)際工作中,java開發(fā)的spring boot等通過jar包部署需要一直運(yùn)行的程序部署到服務(wù)器上時(shí),都希望后臺運(yùn)行,方便管理程序服務(wù)、防止被誤操作關(guān)閉,本文結(jié)合自己工作經(jīng)驗(yàn)講解jar包后臺運(yùn)行的兩種方式,分別是按操作系統(tǒng)支持的特殊方式和統(tǒng)一執(zhí)行命令的方式。
方式一:按操作系統(tǒng)支持的方式后臺運(yùn)行
可執(zhí)行jar包程序可以按操作系統(tǒng)支持的方式運(yùn)行,不同操作系統(tǒng)執(zhí)行命令和方式不一樣,這里主要講解linux操作系統(tǒng)和window操作系統(tǒng)下如何按操作系統(tǒng)支持的特殊方式后臺運(yùn)行。
linux操作系統(tǒng)
Linux操作系統(tǒng)java程序后臺運(yùn)行又主要分如下兩種方式:
1.通過nohup命令和&符號運(yùn)行。
終端關(guān)閉后程序也會繼續(xù)運(yùn)行,示例如下:
nohup java -jar demo.jar > nohup.log 2>&1 &
示例命令說明:
- nohup:使得終端關(guān)閉,運(yùn)行的命令也不中斷。
- java -jar demo.jar:用于啟動jar包。
- nohup.log:標(biāo)準(zhǔn)輸出重定向到nohup.log文件。
- 2>&1:標(biāo)準(zhǔn)錯(cuò)誤重定向到標(biāo)準(zhǔn)輸出(即nohup.log文件)。
- &:命令放入后臺執(zhí)行。
執(zhí)行上述命令后,程序后臺運(yùn)行,日志記錄到nohup.log里,可以使用tail等命令看日志文件,并且會得到一個(gè)進(jìn)程ID(PID,這個(gè)PID可以通過ps ax|grep "demo.jar"查找),可以使用kill命令通過這個(gè)PID來終止進(jìn)程。

2.jar配置為可自啟動的服務(wù)。
在Linux上將jar文件設(shè)置為服務(wù)需要編寫一個(gè)系統(tǒng)服務(wù)單元文件(.service文件),然后使用systemd來管理服務(wù)。以下是一個(gè)示例:
- 創(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ù)開機(jī)自啟:
sudo systemctl enable your-service.service
確保替換 ??<username>??? 和 ??/path/to/your-application.jar??? 為實(shí)際的用戶名和jar文件路徑。如果需要傳遞額外的Java選項(xiàng),可以在 ??ExecStart?? 中添加。
請注意,這個(gè)示例假定你已經(jīng)有權(quán)限執(zhí)行systemctl命令,并且你的系統(tǒng)已經(jīng)安裝了Java運(yùn)行時(shí)環(huán)境(JRE)或Java Development Kit(JDK)。如果沒有安裝Java,你需要先安裝它,通??梢允褂孟到y(tǒng)的包管理器,例如在Ubuntu上使用 ??sudo apt-get install default-jdk??。
window操作系統(tǒng)
要在Windows環(huán)境下使jar包在后臺運(yùn)行,可以使用javaw命令代替java命令,javaw命令不會打開命令行窗口,適合運(yùn)行沒有圖形界面但需要在后臺運(yùn)行的Java應(yīng)用程序;也可以使用??winsw??工具安裝為系統(tǒng)服務(wù)實(shí)現(xiàn)后臺運(yùn)行。
結(jié)合操作系統(tǒng)支持的方式,window下java程序后臺運(yùn)行又主要分如下四種方式:
1.使用javaw -jar demo.jar命令運(yùn)行jar包
打開命令提示符或PowerShell,使用javaw -jar demo.jar命令運(yùn)行jar包。
2.定時(shí)運(yùn)行或開機(jī)自啟
如果需要定時(shí)運(yùn)行或開機(jī)自啟,可以創(chuàng)建一個(gè)批處理文件來運(yùn)行jar包,可以通過Windows任務(wù)計(jì)劃程序來設(shè)置。
示例批處理文件(run-jar.bat):
@echo off start javaw -jar demo.jar exit
3.通過VBS腳本運(yùn)行
如果你想要該進(jìn)程在后臺默默運(yùn)行,可以創(chuàng)建VBS腳本來啟動它:
CreateObject("Wscript.Shell").Run "cmd /c start javaw -jar your-application.jar", 0, True保存為.vbs文件,例如run-jar.vbs,雙擊該文件即可在后臺運(yùn)行jar包。
4.安裝為服務(wù)方式運(yùn)行
將其作為服務(wù)安裝,可以使用??winsw??工具來將你的Java應(yīng)用程序包裝成Windows服務(wù)。這樣可以確保即使命令行關(guān)閉,程序也會繼續(xù)運(yùn)行。
下載winsw的二進(jìn)制文件,并重命名為你的服務(wù)名稱,例如demo.exe。然后創(chuàng)建一個(gè)配置文件demo.xml,最后通過install安裝為windows服務(wù)。
安裝服務(wù)的基本步驟如下:
- 下載winsw二進(jìn)制文件。
- 重命名為demo.exe。
- 創(chuàng)建demo.xml配置文件,指定jar路徑和其他參數(shù)。
- 運(yùn)行demo.exe install來安裝服務(wù)。
- 這樣,你的Java應(yīng)用程序就會作為Windows服務(wù)在后臺運(yùn)行,并可以設(shè)置為開機(jī)啟動。
方式二:統(tǒng)一執(zhí)行命令的方式(Runtime.getRuntime().exec())
方式一雖然都能實(shí)現(xiàn)jar程序后臺運(yùn)行但是方式并不統(tǒng)一,不同操作系統(tǒng)需要按不同方式配置,java程序既然是跨平臺的,為什么個(gè)不能讓jar包后臺運(yùn)行的命令也統(tǒng)一呢?答案是肯定可以的,這兒要講的就是這種方式,實(shí)現(xiàn)也比較簡單,Vertx等項(xiàng)目就是按這種方式,通過java 調(diào)用系統(tǒng)命令實(shí)現(xiàn)(Runtime.getRuntime().exec())。
這種方式目標(biāo)
使用相同啟動命令使得程序可以在不同操作系統(tǒng)上后臺運(yùn)行。
實(shí)現(xiàn)思路(Spring boot項(xiàng)目舉例)
- 程序啟動main方法傳入一個(gè)后臺運(yùn)行的標(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àng)目啟動代碼,這樣就實(shí)現(xiàn)了程序后臺運(yù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包運(yùn)行
if (getJar() != null) {
cmd.add("-jar");
cmd.add(getJar());
} else {
//開發(fā)工具運(yùn)行
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包后臺運(yùn)行兩種方式的文章就介紹到這了,更多相關(guān)java jar包后臺運(yùn)行內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java正則表達(dá)式實(shí)現(xiàn)在文本中匹配查找換行符的方法【經(jīng)典實(shí)例】
這篇文章主要介紹了Java正則表達(dá)式實(shí)現(xiàn)在文本中匹配查找換行符的方法,結(jié)合具體實(shí)例分析了java正則匹配查找換行符的實(shí)現(xiàn)技巧與匹配模式相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2017-04-04
Spring?Boot?啟動參數(shù)之如何優(yōu)雅地控制你的應(yīng)用(最新推薦)
Spring Boot 提供了哪些方式來配置這些啟動參數(shù),今天我們就來詳細(xì)解析 Spring Boot 啟動參數(shù)的各種用法,并附帶代碼示例,讓你可以靈活掌控應(yīng)用的啟動過程,需要的朋友可以參考下2025-04-04
Java快速排序的實(shí)現(xiàn)詳細(xì)代碼及通俗解釋
這篇文章主要介紹了Java快速排序?qū)崿F(xiàn)的相關(guān)資料,快速排序是一種高效的排序算法,通過選擇一個(gè)基準(zhǔn)值將數(shù)組分成兩部分,左邊的元素比基準(zhǔn)值小,右邊的元素比基準(zhǔn)值大,然后遞歸地對這兩部分進(jìn)行排序,需要的朋友可以參考下2025-02-02
在JPA中criteriabuilder使用or拼接多個(gè)like語句
這篇文章主要介紹了在JPA中criteriabuilder使用or拼接多個(gè)like語句,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
MYSQL批量插入數(shù)據(jù)的實(shí)現(xiàn)代碼
非常的實(shí)現(xiàn)原理,代碼較多,建議大家仔細(xì)看看。2008-10-10

