如何将Java程序守护化?

32 浏览
0 Comments

如何将Java程序守护化?

我有一个Java程序,我想在Linux系统上将其变为守护进程。换句话说,我希望在shell中启动它,并在我退出登录后继续运行。我还希望能够干净地停止程序。

我找到了这篇文章,它使用了一种结合了shell脚本和Java代码的方法来实现这一目标。看起来不错,但如果可能的话,我希望有更简单的方法。

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

0
0 Comments

问题的出现的原因是作者经常需要运行一些Java程序,并且希望这些程序满足以下条件:1. 免受sighups的影响;2. 完全与启动它的shell断开连接;3. 生成一个包含stderr和stdout内容的日志文件,并将其显示出来;4. 允许作者在进行其他操作时停止查看正在进行的日志,而不会中断运行的进程。

解决方法是使用以下命令来启动Java程序:nohup java com.me.MyProgram </dev/null 2>&1 | tee logfile.log &。这样的话,即使关闭了终端,Java程序仍然会继续运行,并且生成的日志文件内容可以通过查看logfile.log来查看。

然而,这种使用nohup的方法是一个非常糟糕的主意,因为每次想要启动服务时都需要重新启动系统。

为了解决这个问题,可以使用守护进程(daemonize)的方式来启动Java程序。守护进程是在后台运行的进程,它与终端无关,并且不会受到sighups的影响。它可以随时启动和停止,而不需要重新启动系统。

下面是如何将Java程序守护化的步骤:

1. 创建一个脚本文件,用于启动Java程序。例如,可以创建一个名为start.sh的文件,并在其中添加以下内容:java com.me.MyProgram >> logfile.log &

2. 将脚本文件设置为可执行。可以使用chmod +x start.sh命令来实现。

3. 使用nohup命令和守护进程的方式来启动Java程序:nohup ./start.sh </dev/null 2>&1 &

现在,Java程序将以守护进程的方式运行,满足了作者所需的所有条件。

通过使用守护进程的方式启动Java程序,作者不再需要重新启动系统来启动服务,而只需要运行脚本文件即可。这样方便了作者的操作,并且避免了使用nohup的坏处。

0
0 Comments

在使用Apache Commons Daemon将Java程序作为Linux守护进程或WinNT服务运行时,是否有一种方法能够识别系统或进程的停止和启动呢?

在实际开发中,我们经常需要将Java程序作为守护进程或服务运行,以便能够在后台持续运行,即使用户退出登录或系统重新启动。Apache Commons Daemon提供了一种方便的方式来实现这一点,但是它并没有提供直接的方法来识别系统或进程的停止和启动。

然而,我们可以通过其他方式来实现这一功能。以下是一种解决方法:

1. 使用Java的Runtime类来注册一个关闭钩子(shutdown hook)。关闭钩子是在JVM关闭之前执行的代码块,可以用来执行一些清理操作或通知其他进程。可以使用以下代码将关闭钩子添加到Java程序中:

Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
        // 在这里编写关闭钩子的代码
    }
});

2. 在关闭钩子中,我们可以执行一些必要的操作,例如发送停止信号给其他进程或保存程序状态。具体的操作取决于你的需求。

通过以上的解决方法,我们可以在Java程序中识别系统或进程的停止和启动,并进行相应的处理。这样,我们就能更好地控制和管理我们的Java程序,确保其在后台持续运行,并在需要时能够正确地停止和启动。

0
0 Comments

如何将Java程序设置为守护进程?

问题的原因:如果您不能依赖于其他地方提到的Java Service Wrapper(例如,如果您在没有SW包的Ubuntu上运行),您可能希望采用传统的方法:让您的程序在 /var/run/$progname.pid 中写入其PID,并编写一个标准的SysV init脚本(例如,可以使用ntpd的脚本作为示例,它很简单)。最好还要符合LSB标准。

解决方法:首先,start函数会检查程序是否已经在运行(通过检查 /var/run/$progname.pid 是否存在,并且该文件的内容是正在运行进程的PID),如果没有则运行以下代码:

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

然后,stop函数会检查 /var/run/$progname.pid 文件,检查该文件是否为正在运行的进程的PID,并验证它是否为Java虚拟机(以防止杀死只是重用了来自已死Java守护进程的PID的进程)。然后杀死该进程。

当调用时,我的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用户运行,将守护进程以其他用户身份运行。

除非您从shell中进行,否则无法更改Java的uid或euid,这就是为什么您必须使用sudo来完成的原因...如果您问我,这有点麻烦。如果您以运行的用户对 /var/run 和 /var/log 具有写入权限,那么更容易。

此外,Java编写PID文件/锁文件的理由是为了知道守护进程的初始化阶段是否成功完成(在该阶段末尾进行写入)。

需要注意的是,这个答案是无用的。您希望在创建套接字之后进行fork操作。这只是将进程与shell分离,这是完全不同的事情。

而且,这种情况下使用nohup是一个非常糟糕的主意。

0