75

我有一个 Java 程序,我想在 linux 系统上进行守护进程。换句话说,我想在 shell 中开始运行它,并在我注销后让它继续运行。我也希望能够干净地停止程序。

我发现这篇文章结合使用了 shell 脚本和 Java 代码来解决问题。它看起来不错,但如果可能的话,我想要更简单的东西。

在 Linux 系统上守护 Java 程序的首选方法是什么?

4

11 回答 11

37

Apache Commons Daemon会将您的 Java 程序作为 Linux 守护程序或 WinNT 服务运行。

于 2009-02-10T23:04:17.640 回答
32

如果你不能依赖其他地方引用的Java Service Wrapper(例如,如果你在 Ubuntu 上运行,它没有 SW 的打包版本),你可能想用老式的方式来做:让你的程序在 / 中写入它的 PID var/run/$progname.pid,然后围绕它编写一个标准的 SysV 初始化脚本(例如使用 ntpd 的脚本,它很简单)。最好也使其符合 LSB。

本质上,启动函数测试程序是否已经在运行(通过测试 /var/run/$progname.pid 是否存在,并且该文件的内容是正在运行的进程的 PID),如果没有运行

logfile=/var/log/$progname.log
pidfile=/var/run/$progname.pid
nohup java -Dpidfile=$pidfile $jopts $mainClass </dev/null > $logfile 2>&1

stop 函数检查 /var/run/$progname.pid,测试该文件是否是正在运行的进程的 PID,验证它是否是 Java VM(以免杀死一个简单地从死机中重用 PID 的进程我的 Java 守护进程的实例),然后终止该进程。

调用时,我的 main() 方法将首先将其 PID 写入 System.getProperty("pidfile") 中定义的文件中。

然而,一个主要障碍是:在 Java 中,没有简单而标准的方法来获取 JVM 运行的进程的 PID。

这是我想出的:

private static String getPid() {
    File proc_self = new File("/proc/self");
    if(proc_self.exists()) try {
        return proc_self.getCanonicalFile().getName();
    }
    catch(Exception e) {
        /// Continue on fall-back
    }
    File bash = new File("/bin/bash");
    if(bash.exists()) {
        ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","echo $PPID");
        try {
            Process p = pb.start();
            BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream()));
            return rd.readLine();
        }
        catch(IOException e) {
            return String.valueOf(Thread.currentThread().getId());
        }
    }
    // This is a cop-out to return something when we don't have BASH
    return String.valueOf(Thread.currentThread().getId());
}
于 2009-02-10T23:35:24.087 回答
25

我经常发现自己编写的脚本或命令行基本上看起来像这样,如果我想:

  1. 运行一个不受 sighups 影响的程序
  2. 这与生成它的外壳完全断开,并且
  3. 从 stderr 和 stdout 生成一个日志文件,其中的内容也会显示出来,但是
  4. 允许我停止查看正在进行的日志并执行其他操作,而不会中断正在运行的进程

享受。

nohup java com.me.MyProgram </dev/null 2>&1 | tee logfile.log &
于 2009-02-10T23:27:28.787 回答
15

我更喜欢nohup命令。博客文章说有更好的方法,但我认为它们还不够好。

于 2009-02-10T23:10:43.133 回答
5

你可以试试Java Service Wrapper,社区版是免费的,可以满足你的需求。

于 2009-02-10T23:07:06.167 回答
4

那要看。如果这只是一次性的事情,我想将其守护,然后回家,但通常我等待结果,我可能会这样做:

nohup java com.me.MyProgram &

在命令行。要彻底杀死它,您有很多选择。您可能有一个 SIGKILL 侦听器,或者侦听端口并在建立连接时关闭,定期检查文件。不同的方法有不同的弱点。如果它用于生产,我会多加考虑,并且可能会在 /etc/init.d 中添加一个脚本来阻止它,并进行更复杂的关闭,例如 tomcat 所具有的。

于 2009-02-10T23:10:45.737 回答
4

我在 Ubuntu 上的首选方式是使用 libslack 'daemon' 实用程序。这就是 Jenkins 在 Ubuntu 上使用的(这就是我产生这个想法的地方。)我已经将它用于基于 Jetty 的服务器应用程序,它运行良好。

当您停止守护进程时,它将向 JVM 发出关闭信号。此时,您可以通过使用 Runtime.addShutdownHook() 注册关闭挂钩来执行关闭/清理代码。

于 2012-05-16T15:31:42.357 回答
2

这个问题是关于守护任意程序(不是特定于 java 的),所以一些答案可能适用于您的案例:

于 2009-02-10T23:46:01.020 回答
2

DaemonTools :- 在 UNIX 上管理服务的更简洁的方法https://cr.yp.to/daemontools.html

  1. 从 url https://cr.yp.to/daemontools/install.html安装守护程序工具, 按照那里提到的说明进行操作,如有任何问题,请尝试说明https://gist.github.com/rizkyabdilah/8516303

  2. 在/etc/init/svscan.conf创建一个文件并添加以下行。(仅 cent-os-6.7 需要)

 start on runlevel [12345]
 stop on runlevel [^12345]
 respawn
 exec /command/svscanboot
  1. 在 /service/vm/ 文件夹中创建一个名为run的新脚本并添加以下行。
#!/bin/bash    
echo starting VM 
exec java -jar
/root/learning-/daemon-java/vm.jar

注意:将 Jar 替换为您自己的 Jar 文件。或任何 java 类文件。

  1. 重新启动系统

  2. svstat /service/vm 现在应该已经启动并运行了!

  3. svc -d /service/vm 现在应该关闭 vm !
  4. svc -u /service/vm 现在应该启动 vm 了!
于 2016-02-23T04:48:09.883 回答
0

看看这里:

http://jnicookbook.owsiak.org/recipe-no-022/

获取基于 JNI 的示例代码。在这种情况下,您将对作为 Java 启动的代码进行守护,并在 C 中执行主循环。但也可以将主、守护、服务循环放在 Java 中。

https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo029

JNI 玩得开心!

于 2017-06-05T07:32:50.353 回答
0
nohup java -jar {{your-jar.jar}} > /dev/null &

这可能会奏效。

于 2018-08-14T07:05:34.993 回答