Thread的上下文類加載器和普通類加載器的區別
一、概述
Java 在程序執行期間使用不同類型的類加載器來加載資源。在本教程中,我們將探討 Java 中當前類加載器和線程類加載器的行為差異。
2. 類加載器做什麼?
Java 類加載器定位並加載應用程序執行所需的類。如果請求的類依賴於任何其他資源,它們也會被加載。
我們需要**適當的類加載器來在**Java 程序需要時加載不同類型的類。
3. 類加載器之間的關係
Java 類加載器遵循層次關係。
每個查找或加載類的請求都委託給相應的父類加載器。如果所有的祖先類加載器都找不到一個類,那麼當前的類加載器會嘗試定位它。這裡,“當前類”表示當前執行方法的類。
類加載器之間的這種關係有助於維護應用程序中資源的唯一性。此外,如果一個類已經被父類加載器加載,子類加載器不需要重新加載它。
4. 默認類加載器
類加載器加載各自類路徑中存在的類和資源:
- 系統或應用程序類加載器從應用程序類路徑加載類
- 擴展類加載器在擴展類路徑(
JRE/lib/ext
)上搜索 - Bootstrap 類加載器查看 Bootstrap 類路徑 (
JRE/lib/rt.jar
)
Bootstrap 或 Primordial 類加載器是所有類加載器的父類。它加載 Java 運行時——運行 JVM 本身所需的類。
當前的類加載器以線性、分層的方式搜索資源。如果類加載器找不到一個類,它會拋出java.lang.ClassNotFoundException
給相應的子類加載器。子類加載器然後嘗試搜索該類。
對於在層次結構中的任何類加載器的類路徑上找不到所需資源的情況,我們會收到與java.lang.ClassNotFoundException
相關的錯誤消息作為最終結果。
我們也可以自定義默認的類加載行為。我們可以在動態加載類時顯式指定類加載器。
但是,我們應該注意,如果我們從不同類型的類加載器加載同一個類,這些將被 JVM 視為不同的資源。
5. 上下文類加載器
除了默認的類加載器,J2SE 還引入了上下文類加載器。
Java 中的每個**線程**都有一個關聯的上下文類加載器。
我們可以使用Thread
類的*getContextClassLoader()和setContextClassLoader()*方法訪問/修改線程的上下文類加載器。
上下文類加載器是在創建線程時設置的。如果未顯式設置,則**默認為父線程的上下文類加載器**。
上下文類加載器也遵循層次模型。在這種情況下,根類加載器是原始線程的上下文類加載器。原始線程是操作系統創建的初始線程。
隨著應用程序開始執行,可能會創建其他線程。原始線程的上下文類加載器最初設置為加載應用程序的類加載器,即係統類加載器。
假設我們不為層次結構中任何級別的任何線程更新上下文類加載器。因此,我們可以說,默認情況下,線程的上下文類加載器與系統類加載器相同。對於這樣的場景,如果我們執行*Thread.currentThread().getContextClassLoader()和getClass().getClassLoader()*操作,兩者都會返回相同的對象。
5.1。處理委派問題
當默認 Java 類加載器的類路徑中不存在所需資源時,上下文類加載器非常重要。因此,我們可以使用上下文類加載器來擺脫傳統的線性委託模型。
在類加載器的層次模型中,父類加載器加載的資源對子類加載器可見,反之則不可見。在某些情況下,父類加載器可能需要訪問子類加載器的類路徑中存在的類。
上下文類加載器是實現這一目標的有用工具。我們可以在訪問所需資源時將上下文類加載器設置為所需的值。因此,在上述情況下,我們可以使用子線程的上下文類加載器,並且可以定位存在於子類加載器級別的資源。
5.2.多模塊環境
在設置上下文類加載器屬性時,我們基本上是在切換加載資源的上下文。我們不是在當前類路徑中搜索,而是獲取一個指向不同類路徑的新類加載器。如果我們想從第三方模塊加載資源,或者我們在具有不同類命名空間的環境中工作,這將特別有用。
但是,我們應該在這裡謹慎行事,並將上下文類加載器屬性重置回原始類加載器,以避免將來出現任何差異。
六,結論
在本文中,我們分析了使用上下文類加載器加載無法通過普通類加載器訪問的資源的重要性。我們看到我們還可以選擇臨時更新給定線程的上下文類加載器以加載所需的類。
了解當前方法的工作環境至關重要。我們可以在不同的類路徑上擁有同名的資源。因此,在從多個類加載器加載資源時,我們應該謹慎行事。