JavaアプリをWindowsサービス化する方法

Javaで作成したサーバアプリをWindowsで常駐される必要があったので

Windowsサービス化させてみた。

 

環境は以下の通り。

Javaバージョン:1.7.0.15

・Windows Server 2008 R2 64bit

Eclipse Helios SR2

 

今回は、Tomcatでも使用されているApache Commons Daemon(移行、Daemo)を使用した。

今回試した手順は以下の通り。

 

1. ダウンロード

Daemonに関するライブラリだったりバイナリをダウンロードする。

ライブラリは、

http://commons.apache.org/proper/commons-daemon//download_daemon.cgi

バイナリは、

http://commons.apache.org/proper/commons-daemon//binaries.html

からそれぞれ最新版を入手する。

 

ライブラリは、commons-daemon-1.0.13.jarとバージョン付きのJarファイル

なので、これをプロジェクトのビルドパスに加えておく。

 

2. コーディング

Windowsサービス開始と停止時のエントリポイントとなるクラスを用意する。

このクラスは、org.apache.commons.daemon.Daemonインタフェースを

実装する必要がある。

サービス開始時と停止時にコールされるメソッドを用意する。

このメソッドは、public staticでなければならない。戻り値はどの型でも大丈夫だけど、評価できないのでvoidが妥当。

Linuxで使用する場合は、Daemonインタフェースで定義されているメソッドを

Overrideして処理を記述する必要があるけど、今回はWIndowsなので無視する。

 

サンプルは、以下の通り。

サンプルをビルドして実行可能JarとしてServiceLauncher.jarを作成する。

 

ServiceLauncher.java

package hoge;
  
import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.apache.commons.daemon.DaemonInitException;
 
/**
 * サービスを起動停止するクラス.
 *
 */
public class ServiceLauncher implements Daemon {
 
    // ランチャー
    private static ServiceLauncher launcher;
 
    // サービス
   private Service service;
 
   /**
    * コンストラクタ.
    */
    public Service() {
    }
 
   /** 
    * サービス実行.
    *
    */
    public void run()  {
       
        service = new Service();
            ・
            ・
            ・
        try {
            Thread t = new Thread(service );
            t.setDaemon(true);
            t.start();
            // サービスが停止するまで制御を戻したらダメ
            t.join();
        } catch (InterruptedException e) {
            ・
            ・
        }
    }
  
   /**
    * サービス停止処理
    */
    public void terminate() {
        if (service != null) {
            service .stop();
        }
    }
 
   /**
    * Windowsサービス開始時にcommons Daemonからコールされる
    *
    */
    public static void startService(String args) {
        launcher = new ServiceLauncher();
        launcher.run(); // サービス停止まで制御もどってこないはず
    }
 
   /**
    * Windowsサービス停止時にcommons Daemonからコールされる
    *
    * @param args
    */
    public static void stopService(String args) {
        if (launcher != null) {
            launcher.terminate();
        }
    }
 
   /**
    * Linuxで使用した場合commons Daemonからコールされる
    * 未実装
    */
    @Override
    public void destroy() {
        // Ingore
    }
 
   /**
    * Linuxで使用した場合commons Daemonからコールされる
    * 未実装
    */
    @Override
    public void init(DaemonContext arg0) throws DaemonInitException, Exception {
        // Ingore
    }
 
   /**
    * Linuxで使用した場合commons Daemonからコールされる
    * 未実装
    */
    @Override
    public void start() throws Exception {
        // Ingore
    }
 
   /**
    * Linuxで使用した場合commons Daemonからコールされる
    * 未実装
    */
    @Override
    public void stop() throws Exception {
        // Ingore
    }
 
   /**
    * メイン関数
    * Windowsサービス時には未使用
    * @param args
    */
    public static void main(String[] args) {
        launcher = new ServiceLauncher();
        launcher.run();
        return;
    }
}

 

Service.java

package hoge;
 
/**
 * サービスクラス.
 *
 */
public class Service implements Runnable {
    // 実行中フラグ
    private boolean isRunning = false;
 
   /**
    * コンストラクタ.
    */
    public Service () {
    }
  
   /**
    * サービスを停止する。
    *
    */
    public void stop() {
        isRunning = false;
    }
 
   /**
    * スケジューラを開始する。
    *
    */
    @Override
    public void run() {
        isRunning = true;
 
        while (_isRunning) {
            ・
            ・
            ・
        }
    }
}

 

3. インストール

できあがったJarファイルをWindowsサービスに登録する。

使用するのは、バイナリとしてダウンロードしたprunsvr.exeとprunmgr.exe。

64bit OSで使用する場合は、amd64/にあるファイルを使用する。

 

prunsvr.exeをServiceLauncher.exeにprunmgr.exeをServiceLauncherw.exeに

それぞれリネームする。

上記exeファイルと作成したJarファイルを同じフォルダに置く。

 

パラメータが多いのでインストール用バッチファイルを作成する。

 

Install.bat

set EXEC_DIR=%~dp0
echo %EXEC_DIR%
set INSTALL_PATH=%EXEC_DIR%ServiceLauncher.exe
set CLASSPATH=%EXEC_DIR%ServiceLauncher.jar;<commons-daemon-1.0.13.jarへのパス>
# JVMのパスを指定する。オプションでauto指定もできるがうまくいかない
set JVM_PATH="C:\Program Files\Java\jre7\bin\server\jvm.dll"  
 
 
ServiceLauncher //IS//ServiceLauncher--DisplayName="ServiceLauncher" --Install=%INSTALL_PATH% --Startup=auto --Jvm=%JVM_PATH% --StartMode=jvm --StopMode=jvm --Classpath=%CLASSPATH% --StartClass=hoge.ServiceLauncher --StartMethod=startService --StopClass=hoge.ServiceLauncher --StopMethod=stopService --LogPath=%EXEC_DIR% --LogLevel=DEBUG --StdOutput=auto --StdError=auto
pause  

 

アンインストール用のバッチファイルも用意する。

 

Uninstall.bat

ServiceLauncher //DS//ServiceLauncher 
  
pause  

 

詳細は、

http://commons.apache.org/proper/commons-daemon//procrun.html

http://wiki.apache.org/commons/Daemon

を参照

 

 

4. サービス起動

prunmgr.exeをリネームしたServiceLauncherw.exeからサービスの起動停止を行う。

当然、通常のWindowsサービス起動停止手順でも可能。

 

prunmgr.exeでは他にもパラメータの変更ができる。

prunmgr.exeは、ファイル名=サービス名として認識する。

ファイル名内の'w'は無視するのでサービス名+'w'にリネームしておくと

サービス名にリネームしたprunsvr.exeと共存できるようになる。