杰尔·地狱
什么是JAR地獄? (或者是classpath地獄?還是依賴地獄?)在考慮使用Maven或OSGi等現代開發工具時,哪些方面仍然有意義?
有趣的是,似乎沒有對這些問題的結構化答案(即,即使第二頁也沒有希望的頭條新聞)。 該職位應填補這一空白。
總覽
我們將從構成JAR地獄的一系列問題開始,暫時忽略構建工具和組件系統。 當我們評估當前的狀況時,我們將回到第二部分。
杰爾·地獄
JAR Hell是一個可愛的術語,指的是Java的類加載機制的特性所引起的問題。 其中一些相互依存。 其他人是獨立的。
未表達的依賴性
JAR無法以JVM可以理解的方式來表示它依賴的其他JAR。 需要一個外部實體來識別和實現依賴關系。 開發人員必須通過閱讀文檔,找到正確的項目,下載JAR并將其添加到項目中來手動執行此操作。 可選的依賴項(如果開發人員要使用某些功能,則JAR可能僅需要另一個JAR)會使過程進一步復雜化。
運行時在需要訪問依賴之前,將不會檢測到它們。 這將導致NoClassDefFoundError崩潰正在運行的應用程序。
傳遞依存關系
為了使應用程序正常工作,可能只需要少數幾個庫。 每個反過來可能需要少量其他庫,依此類推。 由于未表達的依賴關系的問題變得更加復雜,因此它變得越來越費力且容易出錯。
遮蔽
有時,類路徑上的不同JAR包含具有相同完全限定名稱的類。 可能由于不同的原因而發生這種情況,例如,當同一庫有兩個不同版本時,或者當胖JAR包含也作為獨立JAR引入的依賴項時,或者當一個庫被重命名并在不知不覺中兩次添加到類路徑時。
因為將從類路徑上的第一個JAR加載類以包含它們,所以該變體將“遮蓋”所有其他類并使它們不可用。
如果變體在語義上有所不同,則可能導致從微妙到通知錯誤的行為到破壞破壞性錯誤的一切。 更糟糕的是,此問題本身表現出來的形式似乎不確定。 這取決于搜索JAR的順序。 這在不同的環境中可能完全不同,例如在開發人員的IDE和最終將運行代碼的生產機器之間。
版本沖突
當兩個必需的庫依賴于第三個庫的不同的,不兼容的版本時,就會出現此問題。
如果兩個版本都存在于類路徑中,則該行為將不可預測。 首先,由于存在陰影,兩個版本中都存在的類將僅從其中一個加載。 更糟糕的是,如果訪問一個中存在但另一個不存在的類,則該類也將被加載。 因此,調用庫的代碼可能會同時找到這兩個版本。
由于需要不兼容的版本,如果缺少其中一個版本,則該程序很可能無法正確運行。 同樣,這可以表現為意外行為或NoClassDefFoundErrors。
復雜類加載
默認情況下,所有應用程序類均由同一類加載器加載,但是開發人員可以自由添加其他類加載器。
這通常是通過組件系統和Web服務器之類的容器完成的。 理想情況下,這種隱式使用對應用程序開發人員是完全隱藏的,但是,眾所周知, 所有抽象都是泄漏的 。 在某些情況下,開發人員可能會明確添加類加載器以實現功能,例如,允許其用戶通過加載新類來擴展應用程序,或者能夠使用具有相同依賴性的沖突版本。
無論多個類加載器如何進入畫面,它們都可以Swift導致顯示出意料之外且難以理解的行為的復雜機制。
類路徑地獄和依賴地獄
Classpath地獄和JAR地獄本質上是同一件事,盡管后者似乎更加關注由復雜的類加載器層次結構引起的問題。 這兩個術語都特定于Java和JVM。
另一方面, 依賴地獄是一個使用更廣泛的術語。 它描述了軟件包及其依賴項的一般問題,適用于操作系統以及各個開發生態系統。 考慮到它的通用性,它并不涵蓋特定于單個系統的問題。
從上面的列表中,它包括可傳遞的和可能未表達的依賴關系以及版本沖突。 類的加載和屏蔽是Java特定的機制,依賴地獄將不會涵蓋這些機制。
發布時間由惠康圖書館在CC-BY 4.0
事態
構建工具
查看問題列表,我們看到構建工具如何幫助解決其中的一些問題。 它們擅長使依賴關系顯式化,以便可以沿著傳遞依賴關系樹的無數邊沿搜尋每個所需的JAR。 這在很大程度上解決了未表達和傳遞依賴的問題。
但是Maven等。 對陰影不做任何事情。 盡管它們通常致力于減少重復的類, 但不能阻止它們 。 除了指出版本沖突之外,構建工具也無助于解決版本沖突。 而且由于類加載是運行時構造,因此它們也不涉及。
組件系統
我從未使用過OSGi或Wildfly之類的組件系統,因此無法證明它們的工作情況。 從他們的說法看來,他們似乎能夠解決大多數JAR地獄問題。
但是,這帶來了額外的復雜性,并且經常要求開發人員更深入地研究類加載器機制。 具有諷刺意味的是,上面的列表中也有一點。
但是,無論組件系統是否確實在很大程度上緩解了JAR地獄的痛苦,我的印象是,絕大多數項目都沒有使用它們。 在這種假設下,絕大多數人仍然遭受與類路徑有關的問題。
這在哪里離開我們?
由于它們未被廣泛使用,因此組件系統不會影響大局。 但是,構建工具的普遍存在大大改變了JAR地獄不同圈子的嚴重性。
我參與或聽說過的任何構建工具都不支持的項目都花費了大量的時間來處理來自未表達或可傳遞依賴的問題。 陰影有時會抬起丑陋的頭,需要花費不同的時間來解決-但最終總是如此。
版本沖突是JAR地獄中最棘手的問題。
但是,每個項目遲早都要依靠相互沖突的版本進行斗爭,并且必須做出一些艱難的決定才能解決這些問題。 通常,必須推遲某些所需的更新,因為這將強制執行當前無法執行的其他更新。
我敢說,對于大多數大小合適的應用程序,服務和庫,版本沖突是何時以及如何更新依賴項的主要決定因素之一。 我覺得這是無法忍受的。
對于非平凡的類加載器層次結構,我經驗不足,無法評估它們有多少重復出現的問題。 但是考慮到我迄今為止從事的所有項目都不需要它們,我敢說它們并不常見。 在網絡上搜索使用它們的原因通常會發現我們已經討論的內容:依賴關系導致版本沖突。
因此,根據我的經驗,我會說版本沖突是JAR地獄中最棘手的問題。
反射
我們已經討論了JAR地獄的構成要素:
- 未表達的依賴性
- 傳遞依賴
- 遮蔽
- 版本沖突
- 復雜類加載
根據為游戲帶來的構建工具和組件系統以及它們的使用范圍,我們得出結論,很大程度上解決了未表達的和可傳遞的依賴關系,這至少掩蓋了緩解和復雜類加載的不常見性。
這使版本沖突成為JAR地獄中最有問題的方面,影響了大多數項目中的日常更新決策。
翻譯自: https://www.javacodegeeks.com/2015/10/jar-hell.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: Java多线程:易失性变量,事前关联和内
- 下一篇: 苹果MAC电脑双系统教程苹果电脑如何做双