web-dev-qa-db-ja.com

優れたLinuxサービスであるためには、Javaプログラムは何をリッスンする必要がありますか?

Linuxでは、次のコマンドを実行できます。

service <someService> start
service <someService> stop

kill -9 <someService>でプロセスを強制終了するのとは対照的です。以前の質問で学んだように、これはプロセスにSIGTERM(前)とSIGKILL(後)を送信することの違いです。

では、通常のJARまたはWARを、これらのコマンドで開始および停止できるサービス/デーモンとして「登録」(およびコーディング)するにはどうすればよいでしょうか。 JavaにはSIGTERMsを処理するためのAPIが必要だと思いますか?

前もって感謝します!

28
IAmYourFaja

シャットダウン固有のコードを実行したいだけの場合、これを処理する「適切なJava」の方法ではシグナルを使用せず、代わりに、アプリケーションが終了しようとしたときに実行される汎用の「シャットダウンフック」を追加します。これは、Javaが時々苦しむ最小公分母の問題の1つです。(すべてのプラットフォームがSIGINTをサポートしているわけではないため、JavaではSIGINTをサポートしているプラ​​ットフォームはありません。)

残念ながら、 ShutdownHook ではあまりコンテキストを取得できませんが、それでも役立つ場合があります。

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    public void run()
    {
        // cleanup
    }
}));

受信したシグナルを本当に区別する必要がある場合、Javaが通常無視するシグナル(USR1など)をサポートする場合、またはシグナルに基づいてシャットダウンを中止する場合、残念ながら、ShutdownHookはほとんど役に立たないでしょう。

Sun.misc.SignalHandlerクラスを使用して、Sun JVMでシグナルをキャプチャするための、サポートされていない、十分に文書化されていない方法があります。 IBM JVMもこれをサポートしている のようですが、これは疑わしいほど移植性があります。

たとえば、シグナルハンドラーを接続して、サーバー構成のSIGHUPリロードをリロードできます。サーバー構成は、init.dスクリプトでreload動詞として設定されています。

Signal.handle(new Signal("HUP"), new SignalHandler() {
    public void handle(Signal signal)
    {
        reloadConfiguration();
    }
});

Javaアプリケーションをsystemコマンドを使用して制御するように構成するには、それを起動するinit.dプログラムでシェルスクリプトを作成する必要があります。これは、単にstartに応答する必要があります。 stop動詞を入力し、適切なアクションを実行します。たとえば、これは/etc/init.d/my-Java-programの場合があります。

#!/bin/sh

case "$1" in
start)
    Java /path/to/my/Java/program.jar &
    echo $! > /var/run/my-Java-program.pid
    ;;

stop)
    if [ ! -f /var/run/my-Java-program.pid ]; then
        echo "my-Java-program: not running"
        exit 1
    fi

    kill -TERM `cat /var/run/my-Java-program.pid`
    ;;

reload)
    if [ ! -f /var/run/my-Java-program.pid ]; then
        echo "my-Java-program: not running"
        exit 1
    fi

    kill -HUP `cat /var/run/my-Java-program.pid`
    ;;

*)
    echo "Usage: /etc/init.d/my-Java-program {start|stop|reload}"
    exit 1
    ;;

esac

exit 0

これで、/etc/init.d/my-Java-program startを実行してアプリケーションを起動できます。または、CentOSでは、サービスmy-Java-programstart`を使用することもできます。

35
Edward Thomson

ネイティブUnixプログラムのように、純粋なJavaでさまざまなシグナルのシグナルハンドラーを定義することはできません。これは、たとえば、の一般的な規則に従うことができないことを意味します。プログラムにSIGHUPで構成を再ロードさせ、SIGINTまたはSIGTERMでクリーンシャットダウンを実行させます。

あなたができることは シャットダウンフック を定義することです。これらは、仮想マシンがシャットダウンするときに実行されます。 SIGTERMを受け取った後。次に例を示します。

Runnable myShutdownHook = new Runnable() {
    void run() {
        System.out.println("I'm melting! What a world...");
    }
};

Runtime.getRuntime().addShutdownHook(new Thread(myShutdownHook));
3
Joni