Java デーモンは、jar パッケージ外の設定ファイルに対する FileInputStreamException が原因で失敗し続けます。

Java デーモンは、jar パッケージ外の設定ファイルに対する FileInputStreamException が原因で失敗し続けます。

標準の Debian Stretch (カーネル バージョン 4.9) を搭載した Raspberry Pi で実行されるデーモン/サービスとして Java アプリケーションを実装したいと考えています。

Java アプリケーションは起動しますが、jar の外部にある重要な構成ファイルを読み取ることができないため、例外がスローされます。これは仕様です。構成ファイルは jar の外部に保持したいのです。

設定ファイルを jar に入れて、InputStream 経由でファイルを読み取ることで実行できました。ただし、設定ファイルは jar 内にないことが条件です。ターミナル経由で jar を手動で起動することもできます。root として手動で起動すると、ファイル権限は問題なく動作するはずです。

私の推測では、サービスの起動中に作業ディレクトリが混乱するのではないかと思います。また、FileInputStream を介してファイル システムをナビゲートすると問題が発生するのではないかと思います。

これは私のサービス ファイルです:

[Unit]
Description=collector

[Service]
User=root
CHDIR=/opt/servicedir/

#application.properties:
ExecStart=/usr/bin/java -jar /opt/servicedir/javaapp.jar
SuccessExitStatus=143
TimeoutStopSec=10
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

/opt/servicedir/ 内のすべてのファイル権限: sudo chmod -R 770 /opt/servicedir/

syslog からの例外:

Aug 31 14:38:58 raspberrypi systemd[1]: myservice.service: Main process exited, code=exited, status=1/FAILURE
Aug 31 14:38:58 raspberrypi systemd[1]: myservice.service: Unit entered failed state.
Aug 31 14:38:58 raspberrypi systemd[1]: myservice.service: Failed with result 'exit-code'.
Aug 31 14:39:03 raspberrypi systemd[1]: myservice.service: Service hold-off time over, scheduling restart.
Aug 31 14:39:03 raspberrypi systemd[1]: Stopped service
Aug 31 14:39:03 raspberrypi systemd[1]: Started service
Aug 31 14:39:04 raspberrypi java[7982]: Exception in thread "main" java.lang.ExceptionInInitializerError
Aug 31 14:39:04 raspberrypi java[7982]: #011at foo.bar.Application.<clinit>(Application.java:20)
Aug 31 14:39:04 raspberrypi java[7982]: #011at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Aug 31 14:39:04 raspberrypi java[7982]: #011at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
Aug 31 14:39:04 raspberrypi java[7982]: #011at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
Aug 31 14:39:04 raspberrypi java[7982]: #011at java.lang.reflect.Method.invoke(Method.java:497)
Aug 31 14:39:04 raspberrypi java[7982]: #011at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
Aug 31 14:39:04 raspberrypi java[7982]: #011at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
Aug 31 14:39:04 raspberrypi java[7982]: #011at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
Aug 31 14:39:04 raspberrypi java[7982]: #011at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Aug 31 14:39:04 raspberrypi java[7982]: Caused by: java.lang.RuntimeException: Failed to load credentials.properties.
Aug 31 14:39:04 raspberrypi java[7982]: #011at foo.bar.Config.<clinit>(Config.java:60)
Aug 31 14:39:04 raspberrypi java[7982]: #011... 9 more
Aug 31 14:39:04 raspberrypi java[7982]: Caused by: java.io.FileNotFoundException: ./res/credentials.properties (Datei oder Verzeichnis nicht gefunden)
Aug 31 14:39:04 raspberrypi java[7982]: #011at java.io.FileInputStream.open0(Native Method)
Aug 31 14:39:04 raspberrypi java[7982]: #011at java.io.FileInputStream.open(FileInputStream.java:195)
Aug 31 14:39:04 raspberrypi java[7982]: #011at java.io.FileInputStream.<init>(FileInputStream.java:138)
Aug 31 14:39:04 raspberrypi java[7982]: #011at java.io.FileInputStream.<init>(FileInputStream.java:93)
Aug 31 14:39:04 raspberrypi java[7982]: #011at foo.bar.Application.Config.<clinit>(Config.java:44)
Aug 31 14:39:04 raspberrypi java[7982]: #011... 9 more
Aug 31 14:39:04 raspberrypi systemd[1]: myservice.service: Main process exited, code=exited, status=1/FAILURE
Aug 31 14:39:04 raspberrypi systemd[1]: myservice.service: Unit entered failed state.
Aug 31 14:39:04 raspberrypi systemd[1]: myservice.service: Failed with result 'exit-code'.

以下は Java コードのコード行です:

    //  this does not work :
    String credentialsFilePath = "./res/credentials.properties"
    try (FileInputStream in = new FileInputStream(credentialsFilePath)) {


    // this line works with the config file inside the jar
    String credentialsInJar = "credentials.properties"
    try (InputStream in = Config.class.getResourceAsStream(credentialsInJar)) {

答え1

systemdユニットに作業ディレクトリを設定していません。意図されましたただし、設定することはできません。

なるほど:

CHDIR=/opt/servicedir/

しかし、そのような設定オプションはありません。

サービスが起動する作業ディレクトリを設定するには、WorkingDirectory=。 例えば:

WorkingDirectory=/opt/servicedir

関連情報