java?jar包后臺運行的兩種方式詳解
前言
在實際工作中,java開發(fā)的spring boot等通過jar包部署需要一直運行的程序部署到服務器上時,都希望后臺運行,方便管理程序服務、防止被誤操作關閉,本文結合自己工作經(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命令和&符號運行。
終端關閉后程序也會繼續(xù)運行,示例如下:
nohup java -jar demo.jar > nohup.log 2>&1 &
示例命令說明:
- nohup:使得終端關閉,運行的命令也不中斷。
- java -jar demo.jar:用于啟動jar包。
- nohup.log:標準輸出重定向到nohup.log文件。
- 2>&1:標準錯誤重定向到標準輸出(即nohup.log文件)。
- &:命令放入后臺執(zhí)行。
執(zhí)行上述命令后,程序后臺運行,日志記錄到nohup.log里,可以使用tail等命令看日志文件,并且會得到一個進程ID(PID,這個PID可以通過ps ax|grep "demo.jar"查找),可以使用kill命令通過這個PID來終止進程。

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

