如何在背景執行 Java 程式
1. 簡介
有時,我們希望在後台運行 Java 程序,即使在終端關閉後仍保持其運作。
在本教程中,我們將探索實現這一目標的各種方法。我們將研究如何將 Java 進程作為獨立會話運行,即使在關閉終端機後仍能繼續運行。
2. 將 Java 作為後台程序運行
在背景執行 Java 程式最簡單的方法之一是使用 shell 腳本中的&
運算子:
#!/bin/sh
java -jar /web/server.jar &
echo $! > startupApp.pid
&
確保該進程在背景運行,讓我們無需等待它完成即可使用終端。
$! > startupApp.pid
擷取並儲存最後執行的後台指令的 PID(進程 ID)。此 PID 唯一地識別正在運行的進程,並且稍後可用於進程管理任務,例如監控或停止它。
然而,這種方法有一個缺點。即使我們可以繼續使用終端,但如果關閉終端,進程仍可能會終止。這可能會導致後台程式意外停止。
此外,由於它不是作為服務進行管理的,因此很難正確控制該過程。我們無法像使用systemd
這樣的適當服務管理員那樣輕鬆查看日誌或啟動/停止進程。
3. 使用 Nohup 保持進程活躍
如果我們不想在關閉會話後結束進程,那麼nohup
就是答案。 nohup
(No Hang Up)讓我們的進程即使在我們關閉會話或終端機後仍繼續運行。
以下是使用nohup
的 shell 腳本:
nohup java -jar /web/server.jar > output.log 2>&1 &
echo $! > startupApp.pid
即使我們關閉終端會話, nohup
仍將保持進程運作。 > output.log 2>&1
部分幫助我們將標準輸出和錯誤輸出重新導向到名為 output.log 的檔案中,以便日後輕鬆檢查日誌(用於偵錯目的)。最後的&
在後台運行該進程。
echo $! > startupApp.pid
將 PID 保存在startupApp.pid
中以供將來使用。
如果我們想終止該進程,我們可以執行以下命令:
kill $(cat startupApp.pid)
4. 將 Java 作為systemd
服務運行(適用於 Linux 伺服器)
為了讓 Java 進程能夠長時間運行並且得到更好的管理,我們需要使用systemd
將它們作為服務進行管理。如果我們使用 Linux 伺服器,則建議採用這種方法。現在讓我們看看如何實現這一目標。
首先,我們需要使用以下命令建立一個.service 檔案:
sudo nano /etc/systemd/system/myjavaapp.service
接下來,將以下內容新增至文件:
[Unit]
Description: Java Background Service
After=network.target
[Service]
ExecStart=/usr/bin/java -jar /web/server.jar
WorkingDirectory=/web
Restart=always
User=root
StandardOutput=append:/var/log/myjavaapp.log
StandardError=append:/var/log/myjavaapp.err
[Install]
WantedBy=multi-user.target
我們正在嘗試定義如何將 Java 應用程式作為後台服務運行。在這種情況下,我們要確保應用程式在啟動時自動啟動並保持運作。
在[Unit]
部分,使用After=network.target,
我們指定它僅在網路可用後啟動。如果我們的 Java 應用程式依賴互聯網或網路服務,這一點很重要。
接下來,在[Service]
部分,我們定義 Java 應用程式應該如何運作。讓我們來分析一下。
ExecStart
告訴systemd
透過執行server.jar
來啟動 Java 應用程式。 WorkingDirectory
定義服務將從哪個資料夾執行。在本例中,它被設定為/web
目錄。
Restart
確保如果應用程式因任何原因崩潰, systemd
將自動重新啟動該應用程式。
接下來,我們將User
屬性設定為root
,這表示服務以root
使用者身分執行。但是,為了更好的安全性,通常建議以非 root 使用者身分執行該服務。
我們也使用StandOutput
和StandardError
屬性來追蹤日誌和錯誤。這些對於分析與應用程式相關的問題很有用。
最後,透過WantedBy=multi-user.target
屬性,我們可以讓 Java 應用程式在系統達到服務正常工作階段時自動啟動,以便服務在 GUI 渲染之前啟動。如果沒有這個配置,我們的服務就不知道何時應該自動啟動。它只是停在那裡,我們必須在每次重啟後手動啟動它。
接下來,我們需要重新載入systemd
並啟用該服務。每當我們建立或修改服務並讓systemd
知道變更時,都需要執行此步驟。
我們需要執行以下命令讓systemd
知道我們新新增(或修改)的服務:
sudo systemctl daemon-reload
接下來,我們需要建立一個指向服務文件的符號連結(快捷方式)。系統將此捷徑放置在一個特殊的資料夾中,並在啟動時檢查,並在multi-user.target
階段啟動該服務。
以下是建立符號連結的命令:
sudo systemctl enable myjavaapp
現在,要啟動 Java 應用程序,我們需要重新啟動系統或執行以下命令:
sudo systemctl start myjavaapp
我們可以使用以下命令來驗證服務是否已啟動:
sudo systemctl status myjavaapp
最後,要停止後台進程,我們可以執行以下命令:
sudo systemctl stop myjavaapp
5. 使用screen
或tmux
將 Java 作為後台進程運行
與systemd
或nohup
不同, screen
和tmux
允許我們在不停止正在運行的進程的情況下從會話中分離(斷開連接),然後稍後重新連接(重新連接)到我們離開的位置。
簡而言之,使用screen
或tmux
,我們可以啟動一個 Java 應用程序,關閉筆記型電腦或失去連接,然後稍後再回來查看同一個終端,就像什麼都沒發生一樣,並且該應用程式將繼續在後台運行。
我們可以將其視為 Windows Hibernate,但僅限於終端機會話。
讓我們使用以下命令:
screen -S myjavaapp java -jar /web/server.jar
要分離,我們需要按下Ctrl+A
,鬆開兩者,然後按D
。為了稍後附加,我們需要執行以下命令:
screen -r myjavaapp
我們可以使用tmux
來實現類似的結果。下面是相同的命令:
tmux new-session -s myjavaapp 'java -jar /web/server.jar'
要分離,我們需要按Ctrl+B
,鬆開兩者,然後按D
。為了稍後附加,我們需要執行以下命令:
tmux attach-session -t myjavaapp
tmux
更現代、更強大、更容易使用,而screen
更簡單,足以滿足基本需求。但是,大多數 Linux 發行版都預先安裝了screen
,而我們可能需要單獨安裝tmux
。
6. 結論
在本文中,我們了解如何將 Java 應用程式作為背景進程運行,探討如何在關閉終端會話後保持其運行,甚至使用日誌對其進行監控。
對於簡單的情況, nohup
或&
就可以,但是對於生產環境,使用系統是更可靠的方法。 screen
和tmux
等工具為我們提供了額外的靈活性,即使在重啟後也可以繼續這個過程,就好像什麼都沒發生一樣。我們需要選擇最適合我們用例的方法。