java jar包后台运行的两种方式详解

 更新时间:2024年07月06日 08:45:19   作者:zoyation  
后台运行jar的方法有多种方法可以实现Java后台运行jar文件,下面介绍其中两种常见的方法,下面这篇文章主要给大家介绍了关于java jar包后台运行的两种方式,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

在实际工作中,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包后台运行内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 教你用Java Swing实现自助取款机系统

    教你用Java Swing实现自助取款机系统

    今天给大家带来的是关于JAVA的相关知识,文章围绕着如何用Java Swing实现自助取款机系统展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Java初学者问题图解(动力节点Java学院整理)

    Java初学者问题图解(动力节点Java学院整理)

    本文通过图文并茂的形式给大家介绍了java初学者问题,非常不错,具有参考借鉴价值,需要的朋友参考下
    2017-04-04
  • Spring中的声明式事务控制详解

    Spring中的声明式事务控制详解

    这篇文章主要介绍了Spring中的声明式事务控制详解,Spring的声明式事务顾名思义就是采用声明的方式来处理事务,这里所说的声明,就是指在配置文件中声明,用在Spring配置文件中声明式的事务处理来代替代码是的处理事务,需要的朋友可以参考下
    2024-01-01
  • Java数据结构之顺序表和链表精解

    Java数据结构之顺序表和链表精解

    我在学习完顺序表后一直对顺序表和链表的概念存在一些疑问,这里给出一些分析和看法,通读本篇对大家的学习或工作具有一定的价值,需要的朋友可以参考下
    2021-09-09
  • JAVA如何判断上传文件后缀名是否符合规范MultipartFile

    JAVA如何判断上传文件后缀名是否符合规范MultipartFile

    这篇文章主要介绍了JAVA判断上传文件后缀名是否符合规范MultipartFile,文中通过实例代码介绍了java实现对上传文件做安全性检查,需要的朋友可以参考下
    2023-11-11
  • Java并发系列之AbstractQueuedSynchronizer源码分析(独占模式)

    Java并发系列之AbstractQueuedSynchronizer源码分析(独占模式)

    这篇文章主要为大家详细介绍了Java并发系列之AbstractQueuedSynchronizer源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • java必学必会之this关键字

    java必学必会之this关键字

    java必学必会之this关键字,java中this的用法进行了详细的分析介绍,感兴趣的小伙伴们可以参考一下
    2015-12-12
  • Elasticsearch 在 Java 中的使用示例教程

    Elasticsearch 在 Java 中的使用示例教程

    本文介绍了如何在Java中使用Elasticsearch,涵盖了连接、基本CRUD 操作、复杂查询、索引管理和聚合操作等方面的内容,通过示例,开发者可以一步步地掌握如何在 Java 项目中集成 Elasticsearch,并利用其强大的搜索和分析功能来构建高效的应用程序,感兴趣的朋友一起看看吧
    2024-08-08
  • java 代理机制的实例详解

    java 代理机制的实例详解

    这篇文章主要介绍了java 代理机制的实例详解的相关资料,这里说明下如何实现代理机制,帮助大家理解掌握这部分内容,需要的朋友可以参考下
    2017-08-08
  • Spring Cache抽象-使用SpEL表达式解析

    Spring Cache抽象-使用SpEL表达式解析

    这篇文章主要介绍了Spring Cache抽象-使用SpEL表达式解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12

最新评论