dot2谜团png_一个类加载的谜团解决了
dot2謎團png
面對一個好老問題
我在應用程序服務器上遇到一些類加載問題。 這些庫被定義為Maven依賴項,因此被打包到WAR和EAR文件中。 不幸的是,其中一些還安裝在應用程序服務器中,但版本不同。 啟動應用程序時,我們遇到了與這些類型的問題相關(guān)的各種異常。 如果您想深入了解,那么有一篇不錯的IBM文章介紹了這些異常。
即使我們知道該錯誤是由類路徑上的某些雙重定義的庫引起的,但仍花了兩個多小時來調(diào)查我們真正需要的版本以及要刪除的JAR。
同一周在水罐上偶然發(fā)生相同的話題
幾天后,我們參加了“您真的得到了Classloaders嗎? 蘇黎世Java用戶協(xié)會會議。 Simon Maple對類加載器進行了非常出色的介紹,并從一開始就介紹了非常深入的細節(jié)。 對于許多人來說,這是一次令人大開眼界的會議。 我還必須注意,Simon工作零周轉(zhuǎn),他為JRebel進行宣傳。 在這種情況下,輔導課程通常偏向于實際產(chǎn)品,即輔導員的面包。 在這種情況下,我認為西蒙絕對是紳士和道德主義者,保持適當?shù)钠胶狻?
創(chuàng)建一個工具,解決神秘問題
只是為了創(chuàng)造另一個
一周后,我花了一些時間來學習程序,而現(xiàn)在我已經(jīng)有幾個星期沒有時間了,所以我決定創(chuàng)建一個小工具,列出所有在類路徑上的類和JAR文件,以便可以更輕松地進行調(diào)查。重復。 我試圖依靠這樣的事實,即類加載器通常是URLClassLoader實例,因此可以調(diào)用getURLs()方法來獲取所有目錄名稱和JAR文件。
在這種情況下,單元測試可能非常棘手,因為該功能與類加載器的行為密切相關(guān)。 務實的是,我決定只做一些從JUnit開始的手動測試,只要代碼是實驗性的即可。 首先,我想看看這個概念是否值得進一步發(fā)展。 我打算執(zhí)行測試,并查看報告沒有重復類的日志語句,然后執(zhí)行相同的運行,但是第二次向類路徑添加一些冗余依賴項。 我使用的是JUnit 4.10,在這種情況下,該版本很重要。
我從命令行執(zhí)行了單元測試,發(fā)現(xiàn)沒有重復的類,我感到很高興。 之后,我從Eclipse執(zhí)行了相同的測試,并且感到驚訝:我冗余定義了21個類!
12:41:51.670 DEBUG c.j.c.ClassCollector - There are 21 redundantly defined classes. 12:41:51.670 DEBUG c.j.c.ClassCollector - Class org/hamcrest/internal/SelfDescribingValue.class is defined 2 times: 12:41:51.671 DEBUG c.j.c.ClassCollector - sun.misc.Launcher$AppClassLoader@7ea987ac:file:/Users/verhasp/.m2/repository/junit/junit/4.10/junit-4.10.jar 12:41:51.671 DEBUG c.j.c.ClassCollector - sun.misc.Launcher$AppClassLoader@7ea987ac:file:/Users/verhasp/.m2/repository/org/hamcrest/hamcrest-core/1.1/hamcrest-core-1.1.jar ...仔細研究一下,我可以很容易地發(fā)現(xiàn)JUnit 4.10具有額外的依賴關(guān)系,如maven所示
$ mvn dependency:tree [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building clalotils 1.0.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ clalotils --- [INFO] com.verhas:clalotils:jar:1.0.0-SNAPSHOT [INFO] +- junit:junit:jar:4.10:test [INFO] | \- org.hamcrest:hamcrest-core:jar:1.1:test [INFO] +- org.slf4j:slf4j-api:jar:1.7.7:compile [INFO] \- ch.qos.logback:logback-classic:jar:1.1.2:compile [INFO] \- ch.qos.logback:logback-core:jar:1.1.2:compile [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.642s [INFO] Finished at: Wed Sep 03 12:44:18 CEST 2014 [INFO] Final Memory: 13M/220M [INFO] ------------------------------------------------------------------------這實際上在4.11中已修復,因此如果我將依賴關(guān)系更改為JUnit 4.11,則不會遇到此問題。 好。 一半的謎團解決了。 但是,為什么maven命令行執(zhí)行未報告雙重定義的類?
擴展日志記錄,越來越多的日志記錄我可以發(fā)現(xiàn)一條線:
12:46:19.433 DEBUG c.j.c.ClassCollector - Loading from the jar file /Users/verhasp/github/clalotils/target/surefire/surefirebooter235846110768631567.jar這個文件里有什么? 讓我們解壓縮它:
$ ls -l /Users/verhasp/github/clalotils/target/surefire/surefirebooter235846110768631567.jar ls: /Users/verhasp/github/clalotils/target/surefire/surefirebooter235846110768631567.jar: No such file or directory該文件不會退出! 看來maven創(chuàng)建了這個JAR文件,然后在測試執(zhí)行完成后將其刪除。 再次谷歌搜索,我找到了解決方案。
Java從類路徑加載類。 可以在命令行上定義類路徑,但是應用程序類加載器還有其他來源可以從中獲取文件。 一個這樣的源是JAR的清單文件。 JAR文件的清單文件可以定義執(zhí)行JAR文件中的類所需的其他JAR文件。 Maven創(chuàng)建一個JAR文件,除了清單文件定義清單中列出了JAR和列出類路徑的目錄外,該文件不包含其他內(nèi)容。 這些JAR和目錄不是由getURLs()方法返回的,因此我的小工具(第一個版本)沒有找到重復的對象。
出于演示目的,我足夠快地在運行mvn test命令時制作了該文件的副本,并獲得以下輸出:
$ unzip /Users/verhasp/github/clalotils/target/surefire/surefirebooter5550254534465369201\ copy.jar Archive: /Users/verhasp/github/clalotils/target/surefire/surefirebooter5550254534465369201 copy.jarinflating: META-INF/MANIFEST.MF $ cat META-INF/MANIFEST.MF Manifest-Version: 1.0 Class-Path: file:/Users/verhasp/.m2/repository/org/apache/maven/surefire/surefire-booter/2.8/surefire-booter-2.8.jar file:/Users/verhasp/.m2/repository/org/apache/maven/surefire/surefire-api/2.8/surefire-api-2.8.jar file:/Users/verhasp/github/clalotils/target/test-classes/ file:/Users/verhasp/github/clalotils/target/classes/ file:/Users/verhasp/.m2/repository/junit/junit/4.10/junit-4.10.jar file:/Users/verhasp/.m2/repository/org/hamcrest/hamcrest-core/1.1/hamcrest-core-1.1.jar file:/Users/verhasp/.m2/repository/org/slf4j/slf4j-api/1.7.7/slf4j-api-1.7.7.jar file:/Users/verhasp/.m2/repository/ch/qos/logback/logback-classic/1.1.2/logback-classic-1.1.2.jar file:/Users/verhasp/.m2/repository/ch/qos/logback/logback-core/1.1.2/logback-core-1.1.2.jar Main-Class: org.apache.maven.surefire.booter.ForkedBooter$實際上,除了定義類路徑的清單文件外,別無其他。 但是為什么Maven會這樣做呢? 索納型人,我個人也認識一些聰明的人。 他們不會白白做任何事情。 創(chuàng)建臨時JAR文件以啟動測試的原因是, 在某些類路徑長度可能超過的操作系統(tǒng)上 ,命令行的長度受到限制 。 即使Java(自Java 6起)本身可以解析類路徑中的通配符 ,也不是maven的選擇。 JAR文件位于Maven存儲庫中的不同目錄中,每個目錄都有長名稱。 通配符解析不是遞歸的,這有充分的理由,即使是通配符解析,您也不希望將所有本地存儲都放在類路徑中。
結(jié)論
- 不要使用JUnit 4.10! 使用舊的或較新的東西,或為意外做好準備。
- 了解什么是類加載器以及它如何工作,做什么。
- 使用對命令行長度的最大大小有極大限制的操作系統(tǒng)。
或只是忍受限制。
還有嗎 你的想法?
翻譯自: https://www.javacodegeeks.com/2014/09/a-classloading-mystery-solved.html
dot2謎團png
總結(jié)
以上是生活随笔為你收集整理的dot2谜团png_一个类加载的谜团解决了的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CUBA 7.2 –有什么新功能?
- 下一篇: 如何启动linux系统(如何启动linu