<sub id="zgbbs"></sub>

    <sub id="zgbbs"><address id="zgbbs"></address></sub>
    <form id="zgbbs"><th id="zgbbs"><big id="zgbbs"></big></th></form>

    <form id="zgbbs"><legend id="zgbbs"></legend></form>

  1. <strike id="zgbbs"><pre id="zgbbs"></pre></strike>

    解鎖Java后臺啟動的奧秘

    2024-12-18 09:12:33

    Java 后臺啟動基本原理

    圖片7.jpg

    Web 服務器與 Servlet 容器協作原理

    在 Java 后臺啟動過程中,Web 服務器與 Servlet 容器的協作起著關鍵作用。當 Web 服務器接收到一個 HTTP 請求后,它會首先判斷請求的內容是靜態數據還是動態數據。對于靜態頁面數據,比如一些純 HTML、CSS、JavaScript 文件等,Web 服務器可以自行處理,直接將對應的靜態資源返回給客戶端。而如果接收到的是動態數據請求,這時就需要 Servlet 容器介入了。Servlet 容器充當 Web 服務器和 Servlet 之間的 “中間人” 角色,Web 服務器會把被請求的 Servlet 的 URI 以及 request 對象轉交給 Servlet 容器。隨后,Servlet 容器負責調用相應的 Servlet 程序來處理該請求,并將 Servlet 處理后的請求結果再返回給 Web 服務器,最終由 Web 服務器傳遞給客戶端。以常見的 Tomcat 作為 Servlet 容器舉例來說,它會接收來自如 Apache 等 Web 服務器轉發過來的請求。Servlet 容器與 Servlet 的交互主要是通過 request 和 response 對象來完成的,Servlet 容器負責創建這些對象并傳遞給 Servlet 程序,Servlet 程序則使用這些對象,并調用它們的方法來與 Servlet 容器進行通信。再說說 Servlet 的生命周期各階段的具體情況,這也是協作過程中的重要部分。首先是加載和實例化階段,容器負責加載和實例化一個 Servlet,這個過程可以發生在引擎啟動的時候,也可能推遲到容器需要該 Servlet 為客戶請求服務的時候。例如,當客戶端第一次請求某個 Servlet 時,Servlet 容器將會根據 web.xml 配置文件實例化這個 Servlet 類,并將其貯存于內存中,后續再有新的客戶端請求該 Servlet 時,一般就不會再重新實例化這個 Servlet 類了,而是多個線程使用這同一個實例。接著是初始化階段,init () 方法用于初始化操作,該方法在 Servlet 的整個生命周期中只被調用一次,主要是讀取永久的配置信息,以及執行其他僅僅需要執行一次的任務,像加載一些初始化參數等。然后是處理請求階段,service () 方法由 Servlet 容器調用,以允許 Servlet 響應一個請求,Servlet 容器會傳遞 javax.servlet.ServletRequest 對象和 javax.servlet.ServletResponse 對象過來,ServletRequest 對象包含客戶端 HTTP 請求信息,ServletrResponse 則封裝 Servlet 響應。在 service () 方法內部,還會根據 HTTP 請求種類的不同,進一步調用像 doGet () 或 doPost () 等方法處理相應的請求。最后是移除實例階段,當服務器決定刪除已經加載的 Servlet 實例之前,會調用 Servlet 的 destroy () 方法,來釋放占用的資源。而且,Servlet 容器通過采用多線程等機制,能夠有效提高執行效率、降低服務器負擔。比如針對同一個 Servlet,容器在第一次收到 HTTP 請求時建立一個 Servlet 實例,后續再收到 http 請求后,無需創建相同 Servlet,僅開啟新的線程來處理請求,避免了為每個請求都創建新的實例對象,減少了資源消耗,提升了整體的運行效率。

    Servlet 對象創建時機解析

    Servlet 對象的創建時機分為兩種情況,一是在 Servlet 容器啟動時創建,二是在 Servlet 容器啟動后創建。在 Servlet 容器啟動時創建 Servlet 對象,這種方式適合那些需要在應用加載時就做一些初始化操作的場景,例如初始化操作比較耗時,像要訪問數據庫來加載一些數據用于后續處理的情況。我們可以通過在配置文件 web.xml 中進行設置來實現容器啟動時創建 Servlet,使用<load-on-startup>標簽,里面設置正整數就代表服務器加載時創建,并且數字還有含義,代表啟動的順序,數字越小、優先級越高,不過要注意 1 已經被默認的 servlet 占用了,所以我們一般從 2 開始起設置。比如配置<load-on-startup>2</load-on-startup>,就可以讓對應的 Servlet 在服務器啟動時就被加載創建。而 Servlet 容器啟動后創建 Servlet 對象,默認情況下就是當第一次訪問 servlet(在瀏覽器中訪問)的時候去創建。這種方式的優勢在于可以減少對服務器內存的浪費,提高服務器啟動的效率;但弊端就是如果有一些要在應用加載時就做的初始化操作,就沒辦法完成了。配置文件對 Servlet 對象創建時機的影響很大,通過在 web.xml 里不同的配置,可以靈活決定 Servlet 是在容器啟動時就創建還是首次訪問時創建。并且,同一類型的 Servlet 對象在容器中是以單例的形式存在的,也就是不管有多少個客戶端請求這個 Servlet,容器中只會存在一個該類型的 Servlet 實例對象,多個線程會共用這一個實例來處理各自的請求,不過這也需要我們在編寫 Servlet 代碼時注意線程安全的問題,避免因多個線程同時訪問同一資源而導致數據不一致等情況出現。例如,如果在 Servlet 方法中采用全局變量,并且以該變量的運算結果作為下一步操作的判斷依據,就可能出現線程不安全的情況,像下面這種偽代碼:所以要謹慎使用成員變量,或者采用一些線程安全的處理方式,比如使用synchronized關鍵字來同步對共享數據點的操作,保證一次只有一個線程可以訪問被保護的區段,以此來避免出現類似的線程安全問題。

    Java 后臺啟動常見方式

    Linux 系統中的方式

    在 Linux 系統里啟動 java 項目有以下幾種常見命令及對應的使用場景與特點:java -jar xxx.jar特點:當前 ssh 窗口被鎖定,可按 CTRL + C 打斷程序運行,或者直接關閉窗口時,程序就會退出。例如我們運行一個簡單的 Java 項目,執行java -jar myproject.jar命令后,就只能在該窗口等待程序運行結束或者手動按 CTRL + C 打斷它,如果關閉了這個終端窗口,那 Java 程序也就隨之停止運行了。這種方式比較適合用于在開發過程中簡單測試 Java 項目,并且需要隨時查看程序輸出信息以及手動控制程序停止的情況。java -jar xxx.jar &特定:當前 ssh 窗口不被鎖定,意味著可以繼續在該窗口執行其他命令操作,不過當窗口關閉時,程序會中止運行。比如在執行java -jar anotherproject.jar &后,我們還能在同一個終端窗口里輸入像ls查看文件列表等其他 Linux 命令,但要是關閉了這個終端窗口,對應的 Java 程序就會停止。它適用于一些不需要長時間持續運行,在終端操作過程中臨時啟動 Java 項目查看效果等場景。nohup java -jar xxxx.jar &nohup意思是不掛斷運行命令,當賬戶退出或終端關閉時,程序仍然運行。當用nohup命令執行作業時,缺省情況下該作業的所有輸出被重定向到nohup.out的文件中,除非另外指定了輸出文件。例如我們執行nohup java -jar longrunningproject.jar &,就算我們退出了當前登錄的賬戶或者關閉了對應的終端窗口,這個 Java 項目依然會在后臺持續運行,對于需要長時間穩定運行的 Java 后臺服務程序,采用這種方式啟動就很合適。nohup java -jar xxxx.jar >temp.txt &command >out.file是將command的輸出重定向到out.file文件,即輸出內容不打印到屏幕上,而是輸出到out.file文件中。采用這種命令方式,不僅具備nohup命令使程序在終端關閉或賬戶退出后仍能運行的特點,還能將原本輸出到控制臺的內容按照我們的要求存放到指定的文件中,方便后續查看程序運行過程中的日志等輸出信息。例如可以將程序運行過程中的報錯信息、關鍵數據輸出等保存下來用于分析排查問題。另外,在 Linux 系統中,還可以通過jobs命令查看后臺運行任務,它會列出所有后臺執行的作業,并且每個作業前面都有個編號。如果想將某個作業調回前臺控制,只需要使用fg + 編號即可,比如fg 23就可以把編號為 23 的后臺任務調回前臺進行操作。

    Windows 系統中的方式

    在 Windows 系統上利用任務計劃程序實現 Java 程序后臺啟動,可按照以下詳細步驟進行操作:編寫 Java 程序首先創建一個簡單的 Java 程序示例,比如以下代碼:將上述代碼保存在HelloWorld.java文件中,這就是一個基礎的 Java 程序代碼,當然實際應用中要根據具體的業務邏輯編寫更為復雜的代碼內容。編譯 Java 程序使用javac命令來編譯 Java 程序,在命令提示符或者 PowerShell 等命令行工具中進入到保存HelloWorld.java文件的目錄下,執行命令javac HelloWorld.java,如果編譯成功,會生成一個名為HelloWorld.class的字節碼文件,這是 Java 程序能夠被運行的基礎。打包成 JAR 文件在項目目錄下,生成一個 JAR 文件,可以使用命令jar cvfm HelloWorld.jar Manifest.txt HelloWorld.class(這里假設已經有符合要求的Manifest.txt文件,它可以包含如Manifest-Version: 1.0、Main-Class: HelloWorld等關鍵信息用于指定 JAR 文件的一些屬性以及啟動類等內容)。這樣就把 Java 程序打包成了一個可執行的 JAR 文件,方便后續統一進行部署和啟動操作。配置任務計劃程序打開 Windows 的任務計劃程序,選擇 “創建基本任務”,并設置任務名稱和描述。在 “觸發器” 中選擇合適的觸發條件,例如可以選擇 “在系統啟動時” 自動啟動 Java 程序,或者按照特定的時間計劃來觸發運行。接著在 “操作” 中,選擇 “啟動程序”,然后找到java.exe的路徑(一般在 Java 安裝目錄下的bin文件夾中,比如C:\Program Files\Java\jdk1.8.0_251\bin\java.exe),后面加上參數-jar [你的JAR文件路徑](例如-jar C:\path\to\HelloWorld.jar)。完成以上配置后,保存這個任務設置,之后系統就會按照設定的條件來啟動對應的 Java 程序,使其在后臺運行了。通過這樣一套流程,就可以實現在 Windows 系統上讓 Java 程序在后臺自動啟動運行,滿足如定時任務執行、后臺服務持續運行等各種實際開發和應用的需求。

    Java 后臺啟動注意事項

    資源相關注意點

    在后臺運行 Java 程序時,有幾個資源相關的方面需要我們著重留意。首先是程序日志輸出,這是非常關鍵的一點。合理的日志輸出能夠幫助我們后續排查問題、了解程序運行狀態等。但如果不注意規范,也會帶來不少麻煩。一方面,要避免日志輸出過多的情況,有些人可能為了方便問題排查,在短短 50 行代碼里有一半都在打印日志,要知道打印日志是存在一定性能消耗的,比如一個原本 100ms 就能執行完的方法,可能其中 50ms 都花費在了打印日志上,而且還增加了日志的存儲成本。像在循環體內大量打印日志這種批量打印的情況,就應該盡量避免另外,也要防止日志重復打印的問題,比如方法的調用方和被調用方都打印了相同的內容,或者可以合為一條打印的卻分成多次打印等情況。同時,還需按照正確的日志級別進行輸出,像 debug、info、warn、error 這些級別要區分清楚,error 級別只記錄系統邏輯出錯、異?;蛘咧匾腻e誤信息等,并且建議使用占位符的方式輸出日志,這樣比使用 String 拼接要高效,還要盡量使用英文輸出日志,能有效減少日志存儲大小,也更符合國際化標準。在日志的保存方面,阿里開發手冊建議日志文件至少保留 15 天,對于涉及敏感信息、安全等相關記錄的,根據國家法律要求至少保留六個月,所以要合理規劃日志的存儲和清理策略,防止磁盤空間被日志占滿影響系統穩定性,比如可以采用滾動日志并且定時清除舊文件的方式。其次是錯誤信息處理,當程序出現錯誤時,要確保錯誤信息能夠準確地被記錄下來,方便我們快速定位問題根源,知曉是程序邏輯出錯、存在隱含風險還是其他方面的原因,進而采取相應的解決措施。再者就是要及時釋放資源,避免內存泄漏的情況發生。內存泄漏是指分配的內存無法正確釋放,可能導致性能下降和程序崩潰。比如在使用像文件輸入流(FileInputStream)等資源時,如果沒有在使用完后及時關閉它那么在程序執行后,文件輸入流仍然保持打開狀態,占用內存資源,從而導致內存泄漏。所以我們要使用 finally 塊或 try-with-resources 語句來確保在使用后關閉資源。還有像避免長生命周期的對象持有短生命周期對象的引用,若一個長生命周期的對象持有了一個短生命周期對象的引用,即使短生命周期對象已經不再需要,由于長生命周期對象的存在,垃圾回收器也無法回收短生命周期對象的內存。另外,要慎重使用靜態變量,因為靜態變量的生命周期與應用程序一樣長,使用不當可能意外地阻止對象的回收,也要小心避免循環引用等情況,防止對象無法被正常垃圾回收。同時,我們還可以借助一些內存泄漏檢測工具,如 MAT 和 VisualVM 等來分析堆內存中的對象,查找潛在的內存泄漏問題。

    特殊報錯及解決思路

    在 Java 后臺啟動過程中,常常會遇到一些特殊報錯,下面講講常見的問題及對應的解決辦法或排查思路。

    端口占用問題

    當我們啟動 Java 程序時,可能會遇到端口被占用的報錯,比如出現類似 “Web server failed to start. Port 8080 was already in use.” 這樣的提示,這意味著你嘗試運行的 Java 應用所需的特定網絡端口已經被其他進程占用了,從而導致 Java 程序無法正常啟動。在 Linux 或 Mac OS 系統中,可以使用命令 “lsof -i : 端口號” 來檢查某個特定端口的占用情況,例如查看 80 端口的使用情況,就執行 “lsof -i :80”。而在 Windows 系統中,則可以使用 “netstat -ano | findstr : 端口號” 這個命令,比如查看 80 端口的占用情況,就輸入 “netstat -ano | findstr :80”,上述命令會列出占用該端口的進程 ID(PID)。找到占用端口的進程 ID 后,在 Linux 或 Mac OS 中,可以使用命令 “kill -9 進程 ID” 來殺掉該進程;在 Windows 系統中可以使用 “taskkill /F/PID 進程 ID” 命令,強制停止占用端口的進程,釋放端口以供其他程序使用。另外,如果不想或無法結束占用端口的進程,還可以選擇修改 Java 程序的端口,在代碼中進行設置在上面的示例中,創建了一個新的 ServerSocket 對象并設置了一個新的端口(8080),如果這個端口已經被占用,程序將捕獲異常并輸出提示信息。還有一種情況,在某些情況下,系統防火墻可能會阻止 Java 應用程序訪問特定端口,這時要確保在防火墻設置中允許你設置的端口(如 8080)進行數據傳輸。

    服務啟動失敗報錯

    有時候會遇到服務啟動失敗的報錯情況,比如在 Windows 系統中將.bat 文件注冊成 windows 服務時,可能會出現 “服務啟動失?。哄e誤碼 1053,服務沒有及時響應啟動或控制請求” 這樣的問題,這是因為 windows 服務默認啟動超時時間為 30s,但是有些服務的啟動時間可能會超過 30s,這時就需要修改注冊表來解決該問題,注冊表地址為:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/ServicesPipeTimeout,ServicesPipeTimeout 可能不存在,如果不存在需要自己手動添加,類型為 DWORD,單位是毫秒,不過修改這個設置需要重啟服務器,要根據實際服務器情況來決定是否采用這種方式解決。再比如將 jar 包做成 windows 服務時,可能會遇到執行注冊命令出現報錯,像 “.exe 文件不是有效的 windows32 位應用程序” 這種情況,這時就需要仔細檢查相關版本、文件等是否存在問題,也可以通過網上提供的一些解決方案,如查看是否是病毒原因,是否需要刪除.exe 注冊表等去嘗試解決問題??傊龅椒諉邮箦e時,要仔細查看報錯提示信息,分析可能出現


    聲明:此篇為墨韻科技原創文章,轉載請標明出處鏈接: http://www.26333com.com/news/4538.html
    • 網站建設
    • SEO
    • 信息流
    • 短視頻
    合作伙伴
    在線留言
    服務熱線

    服務熱線

    15879069746

    微信咨詢
    返回頂部
    在線留言
    精品国产污网站在线观看15