java jar包后台运行的两种方式详解
作者:zoyation
前言
在实际工作中,java开发的spring boot等通过jar包部署需要一直运行的程序部署到服务器上时,都希望后台运行,方便管理程序服务、防止被误操作关闭,本文结合自己工作经验讲解jar包后台运行的两种方式,分别是按操作系统支持的特殊方式和统一执行命令的方式。
方式一:按操作系统支持的方式后台运行
可执行jar包程序可以按操作系统支持的方式运行,不同操作系统执行命令和方式不一样,这里主要讲解linux操作系统和window操作系统下如何按操作系统支持的特殊方式后台运行。
linux操作系统
Linux操作系统java程序后台运行又主要分如下两种方式:
1.通过nohup命令和&符号运行。
终端关闭后程序也会继续运行,示例如下:
nohup java -jar demo.jar > nohup.log 2>&1 &
示例命令说明:
- nohup:使得终端关闭,运行的命令也不中断。
- java -jar demo.jar:用于启动jar包。
- nohup.log:标准输出重定向到nohup.log文件。
- 2>&1:标准错误重定向到标准输出(即nohup.log文件)。
- &:命令放入后台执行。
执行上述命令后,程序后台运行,日志记录到nohup.log里,可以使用tail等命令看日志文件,并且会得到一个进程ID(PID,这个PID可以通过ps ax|grep "demo.jar"查找),可以使用kill命令通过这个PID来终止进程。
2.jar配置为可自启动的服务。
在Linux上将jar文件设置为服务需要编写一个系统服务单元文件(.service文件),然后使用systemd来管理服务。以下是一个示例:
- 创建服务单元文件
/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
中添加。
请注意,这个示例假定你已经有权限执行systemctl命令,并且你的系统已经安装了Java运行时环境(JRE)或Java Development Kit(JDK)。如果没有安装Java,你需要先安装它,通常可以使用系统的包管理器,例如在Ubuntu上使用 sudo apt-get install default-jdk
。
window操作系统
要在Windows环境下使jar包在后台运行,可以使用javaw命令代替java命令,javaw命令不会打开命令行窗口,适合运行没有图形界面但需要在后台运行的Java应用程序;也可以使用winsw
工具安装为系统服务实现后台运行。
结合操作系统支持的方式,window下java程序后台运行又主要分如下四种方式:
1.使用javaw -jar demo.jar命令运行jar包
打开命令提示符或PowerShell,使用javaw -jar demo.jar命令运行jar包。
2.定时运行或开机自启
如果需要定时运行或开机自启,可以创建一个批处理文件来运行jar包,可以通过Windows任务计划程序来设置。
示例批处理文件(run-jar.bat):
@echo off start javaw -jar demo.jar exit
3.通过VBS脚本运行
如果你想要该进程在后台默默运行,可以创建VBS脚本来启动它:
CreateObject("Wscript.Shell").Run "cmd /c start javaw -jar your-application.jar", 0, True
保存为.vbs文件,例如run-jar.vbs,双击该文件即可在后台运行jar包。
4.安装为服务方式运行
将其作为服务安装,可以使用winsw
工具来将你的Java应用程序包装成Windows服务。这样可以确保即使命令行关闭,程序也会继续运行。
下载winsw的二进制文件,并重命名为你的服务名称,例如demo.exe。然后创建一个配置文件demo.xml,最后通过install安装为windows服务。
安装服务的基本步骤如下:
- 下载winsw二进制文件。
- 重命名为demo.exe。
- 创建demo.xml配置文件,指定jar路径和其他参数。
- 运行demo.exe install来安装服务。
- 这样,你的Java应用程序就会作为Windows服务在后台运行,并可以设置为开机启动。
方式二:统一执行命令的方式(Runtime.getRuntime().exec())
方式一虽然都能实现jar程序后台运行但是方式并不统一,不同操作系统需要按不同方式配置,java程序既然是跨平台的,为什么个不能让jar包后台运行的命令也统一呢?答案是肯定可以的,这儿要讲的就是这种方式,实现也比较简单,Vertx等项目就是按这种方式,通过java 调用系统命令实现(Runtime.getRuntime().exec())。
这种方式目标
使用相同启动命令使得程序可以在不同操作系统上后台运行。
实现思路(Spring boot项目举例)
- 程序启动main方法传入一个后台运行的标志参数,比如为start。
- main方法里获取args参数判断是否包含start参数,如果包含就获取启动命令和按操作系统设置其他启动参数,然后通过java 调用系统命令方式(Runtime.getRuntime().exec())再次执行不包括start参数的启动命令。
- 通过java 调用系统命令方式(Runtime.getRuntime().exec())再次执行不包括start参数的启动命令后,又进入main方法,main方法args参数里没有start参数,就执行Spring boot项目启动代码,这样就实现了程序后台运行。
执行命令示例:
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 { //开发工具运行 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包后台运行内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!