2008-09-26 74 views
27

我剛剛解決了另一個問題*雖然我當時正在使用這個版本的庫 - 但是顯然 - my-app-server-has-already-loaded-an-old-version-of-this-library- *問題(嘆氣)。Classloader問題 - 如何確定加載哪個庫版本(jar文件)

有沒有人知道驗證(或監視)你的應用程序是否可以訪問所有合適的jar文件或加載的類版本的好方法?

在此先感謝!

[P.S.一個很好的理由,開始使用在我看來,OSGi module architecture]

更新This文章幫助的!它讓我瞭解了將JBoss的類加載器寫入日誌文件的類。

回答

18

如果你碰巧在使用JBoss,有一個MBean(類加載器庫iirc),您可以在其中請求所有加載了某個類的類加載器。

如果一切都失敗了,總會有'java -verbose:class',它將打印每個正在加載的類文件的jar的位置。

+0

聽起來像我可以使用湯姆!我明天會深入研究。在此先感謝.... 約翰 – 2008-09-29 20:49:50

2

我不認爲有一個很好的方法來檢查。我不確定你想這麼做。你需要做的是熟悉你的應用程序服務器的類加載架構,並理解它是如何工作的。

它是如何工作的簡單解釋是:EJB或Web應用程序將首先在其自己的模塊(ejb-jar或war)中聲明的庫中查找類或資源。如果在那裏沒有找到該類,那麼類加載器將請求轉發給其父類加載器,該加載器可以是聲明的依賴項(通常是ejb),也可以是應用程序類加載器,它負責加載在耳包中聲明的庫和資源。如果仍未找到類或資源,請求將轉發到將在其自己的類路徑中查找的應用程序服務器。

這就是說,你應該記住,一個Java EE模塊(Web應用程序,ejb)將始終從最近範圍內的jar中加載類。例如,如果您將log4j v1打包在war文件中,將log4j v2打包爲耳朵級別,並且將log4j v3放入應用程序服務器的類路徑中,則該模塊將在其自己的模塊中使用該jar。拿走它,它會使用耳邊的一個。把它拿出來,它將使用應用程序服務器的類路徑中的一個。如果模塊之間存在複雜的依賴關係,事情會變得更加棘手。

最好是將應用程序全局庫放在耳邊。

+0

對於JBoss至少,它不是那麼簡單。在某些情況下,即使該類存在* WAR文件內部,JBoss也會從WAR文件的外部*(例如,從server/default/lib)加載一個類。它取決於各種因素,例如是否啓用了範圍加載(JBoss版本的默認值不同)以及是否啓用對父類存儲庫的委派。 – 2009-09-09 05:01:30

0

必須有比我做的更好的方式,但我傾向於以非常手動的方式做到這一點。

  1. 每個Jar都必須在文件名中有它的版本號(如果它沒有改變它的名字)。
  2. 每個應用程序都有它自己的類路徑。
  3. 必須有一個理由開始使用更新的Jar(新版本)。不要只是因爲它可用而改變,因爲它可以爲你提供所需的功能。
  4. 每個版本都必須包含所有需要的罐子。
  5. 我保留一個Version類,它知道它需要的Jars列表(它被編碼到源文件中),並且可以在運行時根據類路徑中的Jars列表進行檢查。

正如我所說,它是手動的,但它的工作原理。

3

在當前的Java版本中,庫版本控制是一個相當毛茸茸的術語,它依賴於使用有效清單正確打包的JAR。即使這樣,運行中的應用程序也需要很多工作來以有用的方式收集這些信息。JVm運行時不會給你任何幫助。

我認爲你最好的選擇是在構建時使用像Ivy或Maven這樣的依賴管理工具來獲取正確的版本。有趣的是,Java 7可能會包含一個適當的模塊版本控制框架來完成這種事情。這並不能幫助你,

5

如果在jar清單中有適當的版本信息,則有檢索和測試版本的方法。無需手動讀取清單。

java.lang.Package .getImplementationVersion()和getSpecificationVersion()和isCompatibleWith()聽起來就像他們會做你正在尋找的東西。

您可以通過其他方式獲取帶有this.getClass()。getPackage()的Package。

java.lang.Package的javadoc沒有爲這些屬性提供特定的清單屬性名稱。一個快速谷歌搜索轉向它在http://java.sun.com/docs/books/tutorial/deployment/jar/packageman.html