Debian
由於 jar 包之外的配置文件的 FileInputStreamException,Java 守護程序一直失敗
我想用標準的 Debian Stretch(核心版本 4.9)將 Java 應用程序實現為在我的 Raspberry Pi 上執行的守護程序/服務。
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/
來自系統日誌的異常:
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)) {
您尚未在 systemd 單元中設置工作目錄。不過,看起來您打算設置一個。
我懂了:
CHDIR=/opt/servicedir/
但是沒有這樣的配置選項。
要設置服務啟動的工作目錄,請使用
WorkingDirectory=
. 例如:WorkingDirectory=/opt/servicedir