【问题标题】:How to Daemonize a Java Program?如何守护 Java 程序?
【发布时间】:2010-10-06 18:51:53
【问题描述】:

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

我找到了this article,它结合使用了 shell 脚本和 Java 代码来解决问题。看起来不错,但如果可能的话,我想要更简单的。

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

【问题讨论】:

标签: java process daemon


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    如果你不能依赖 Java Service Wrapper 引用 elsewhere(例如,如果你在 Ubuntu 上运行,它没有 SW 的打包版本)你可能想用老式的方式来做:让你的程序在 /var/run/$progname.pid 中写入它的 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());
    }
    

    【讨论】:

    • 不需要Java写PID,脚本也可以写(echo $!> /var/run/my.pid)另外,因为通常只有root可以写/var /run 你可以让shell脚本以root身份运行,守护进程以另一个用户身份运行。
    • 除非你不能在java中改变uid或euid,所以你必须从shell来做,用sudo......如果你问我,这有点痛苦。让 /var/run 和 var/log 对您运行的用户可写更容易......
    • 另外,让 Java 写入 pid 文件/锁定文件的基本原理是为了知道守护程序的初始化阶段是否成功完成(通过在该阶段结束时写入)。
    • 这个答案没用。您想在创建套接字之后进行分叉。这只是将进程与 shell 分离,这是完全不同的事情。
    • cop-out 选项不起作用——线程 id 几乎肯定与进程 id 不同。
    【解决方案3】:

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

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

    享受吧。

    nohup java com.me.MyProgram &lt;/dev/null 2&gt;&amp;1 | tee logfile.log &amp;

    【讨论】:

    • 您可以使用 cron 和 @reboot 功能启动它。
    【解决方案4】:

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

    【讨论】:

    • 它没有完全守护进程..如果操作系统重新启动怎么办?.这是使用 daemontools stackoverflow.com/a/35569052/1840774 的更干净的解决方案
    • 一旦系统宕机或重启,这将不会启动服务!
    【解决方案5】:

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

    【讨论】:

    【解决方案6】:

    这取决于。如果只是一次性的事情,我想守护它然后回家,但通常我等待结果,我可能会这样做:

    nohup java com.me.MyProgram &
    

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

    【讨论】:

    【解决方案7】:

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

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

    【讨论】:

      【解决方案8】:

      This 问题是关于对任意程序(不是特定于 java 的)进行守护进程,因此某些答案可能适用于您的情况:

      【讨论】:

        【解决方案9】:

        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 现在应该关闭虚拟机了!。
        4. svc -u /service/vm 现在应该启动 vm 了!。

        【讨论】:

          【解决方案10】:
          nohup java -jar {{your-jar.jar}} > /dev/null &
          

          这可能会奏效。

          【讨论】:

            【解决方案11】:

            看这里:

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

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

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

            享受 JNI 的乐趣!

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-09-16
              • 1970-01-01
              • 2011-12-02
              相关资源
              最近更新 更多