目的
- 業務でwindowsサービス化したアプリを使って、別アプリの起動を制御する必要があった。
- こちらを参考にしたが、インターフェースが変わっていたり動かなかったので、令和最新版として記載しておく。
前提条件
- windows 11環境で確認。
- Apache DaeamonでJavaアプリをwindows サービス化した。
- Java8 32bitで確認。Java8 64bitでも動くらしいが、そちらは未確認。
- ソースコードは以下に格納。動かす際はC直下においてください。
- MavenとVisual Studio Codeを使用して開発した。
- JavaアプリはアーカイブしたJARを使用。また、windowsのユーザ権限の問題か、JARの置き場所はユーザのフォルダの配下では動かず、C直下で確認した。
詳細設計
- パッケージcom.exampleの中にServiceLauncherとServiceの2つのクラスがある。
- ServiceLauncherはServiceクラスを管理するクラスで、windowsサービスからApache Deamon経由で呼び出されるクラス。public static void startService(String args)およびpublic static void stopService(String args)の2つのメソッドを実装する必要がある。
- Serviceクラスは実際になんらかの処理を行うクラス。今は無限ループで10秒に一回ログを出力するクラス。
実装
package com.example;
import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.apache.commons.daemon.DaemonInitException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* サービスを起動停止するクラス.
*
*/
public class ServiceLauncher implements Daemon {
// ランチャー
private static ServiceLauncher launcher;
// サービス
private Service service;
private static final Logger logger = LogManager.getLogger(ServiceLauncher.class);
/**
* サービス実行.
*
*/
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) {
logger.info("start startService");
launcher = new ServiceLauncher();
launcher.run(); // サービス停止まで制御もどってこないはず
logger.info("end startService");
}
/**
* Windowsサービス停止時にcommons Daemonからコールされる
*
* @param args
*/
public static void stopService(String args) {
logger.info("start stopService");
if (launcher != null) {
launcher.terminate();
}
logger.info("stop stopService");
}
/**
* 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) {
logger.info("start main");
launcher = new ServiceLauncher();
launcher.run();
logger.info("end main");
return;
}
}
package com.example;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* サービスクラス.
*
*/
public class Service implements Runnable {
// 実行中フラグ
private boolean isRunning = false;
private static final Logger logger = LogManager.getLogger(ServiceLauncher.class);
/**
* コンストラクタ.
*/
public Service () {
}
/**
* サービスを停止する。
*
*/
public void stop() {
isRunning = false;
}
/**
* スケジューラを開始する。
*
*/
@Override
public void run() {
isRunning = true;
logger.info("start run");
while (isRunning) {
logger.info("isRunning");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
logger.info("end run");
}
}
バッチ
- windowsサービスに上記JARを登録するinstall.batと登録解除を行うuninstall.batがある。
- 起動確認はwindowsサービスを起動してServiceLauncherを確認する。
set EXEC_DIR=%~dp0
echo %EXEC_DIR%
pushd %~dp0..
set PROJECT_ROOT=%CD%
popd
echo %PROJECT_ROOT%
set INSTALL_PATH=%EXEC_DIR%commons-daemon-1.3.4-bin-windows\ServiceLauncher.exe
rem set INSTALL_PATH=%EXEC_DIR%commons-daemon-1.3.4-bin-windows\prunsrv.exe
@REM set CLASSPATH="%PROJECT_ROOT%\target;%PROJECT_ROOT%\target\java_deamon_sample-jar-with-dependencies.jar"
set CLASSPATH="C:\java_deamon_sample-jar-with-dependencies.jar"
rem JVMのパスを指定する。オプションでauto指定もできるがうまくいかない
set JavaHome="C:\Program Files (x86)\Eclipse Adoptium\jdk-8.0.392.8-hotspot\jre"
set JVM_PATH="C:\Program Files (x86)\Eclipse Adoptium\jdk-8.0.392.8-hotspot\jre\bin\server\jvm.dll"
rem cd commons-daemon-1.3.4-bin-windows
commons-daemon-1.3.4-bin-windows\ServiceLauncher.exe //IS//ServiceLauncher --DisplayName=ServiceLauncher --Install=%INSTALL_PATH% --Classpath=%CLASSPATH% --Startup=auto --JavaHome=%JavaHome% --Jvm=%JVM_PATH% --StartMode=jvm --StopMode=jvm --StartClass=com.example.ServiceLauncher --StartMethod=startService --StopClass=com.example.ServiceLauncher --StopMethod=stopService --LogPath=%EXEC_DIR% --LogLevel=DEBUG --StdOutput=auto --StdError=auto
rem cd commons-daemon-1.3.4-bin-windows
rem ServiceLauncher.exe //IS//ServiceLauncher --DisplayName=ServiceLauncher --Install=%INSTALL_PATH% --Classpath=%CLASSPATH% --Startup=auto --JavaHome=%JavaHome% --Jvm=%JVM_PATH% --StartMode=jvm --StopMode=jvm --StartClass=com.example.ServiceLauncher --StartMethod=startService --StopClass=com.example.ServiceLauncher --StopMethod=stopService --LogPath=%EXEC_DIR% --LogLevel=DEBUG --StdOutput=auto --StdError=auto
REM ++JvmOptions=-Dlog4j.configurationFile=%PROJECT_ROOT%setting\log4j2.xml
pause
rem commons-daemon-1.3.4-bin-windows\ServiceLauncher.exe //DS//ServiceLauncher
cd commons-daemon-1.3.4-bin-windows
ServiceLauncher.exe //DS//ServiceLauncher
pause