2009-06-03 87 views
30

有沒有一種方法可以確定哪些類在運行時從哪些jar加載?如何研究從哪個JAR加載哪些類?

我確定我們以前都在JAR地獄。我已經解決了這個問題,在項目上排查了ClassNotFoundException s和NoClassDefFoundError。我想避免在jar中找到所有類的實例,並使用代碼中的淘汰過程導致CNFE找到罪魁禍首。

任何分析或管理工具是否會爲您提供此類信息?

這個問題純粹是因爲我們應該在類加載的時候有這個信息。必須有一種方法可以找到它,或者記錄它並找到它,但我知道沒有什麼能做到這一點,是嗎?

我知道OSGi和版本化捆綁包/模塊旨在使這是一個非問題...但它似乎不會很快消失。 :)

注意:我發現這question是我的問題的一個子集,涉及從版本化的罐子加載的類。

更新:有點相關,這篇文章解釋了一種策略來搜索罐子(在當前目錄下)或M2_REPO中的類。 JarScan, scan all JAR files in all subfolders for specific class

更新2:也有點關係,JBoss Tattletale

+0

傑森一天都有它的權利,這基本上是一個問題的副本,我問不是很久以前。 http://stackoverflow.com/questions/779650/where-on-the-file-system-was-my-java-class-loaded-from – shsteimer 2009-06-03 21:35:44

回答

56

跑過-verbose:class切換到java命令將打印裝載每個類和它被從加載。

Joops也是提前找到缺失類的好工具。

+2

我剛剛嘗試過-verbose:class選項。太棒了!!!真的很有幫助 – OscarRyz 2009-06-03 21:04:04

+0

不錯 - 喬布斯看起來很酷 - 你知道它是否足夠聰明,可以跟隨通過Class.forName引用的類嗎? – cwash 2009-06-03 22:08:32

14

從代碼,您可以撥打:

myObject.getClass().getProtectionDomain().getCodeSource() 

(注意,getProtectionDomain可不幸的是返回null(糟糕的設計),這樣 「正確的代碼」 將檢查這一點。)

4

沒有爲一個MBean上面的Jason Day提到的JVM標誌。

如果您使用的是JBoss,那麼如果您將本地JMX MBean服務器添加到您的配置中,則可以使用JMX按需轉換此操作。添加以下-D的:

-Dcom.sun.management.jmxremote.port=3333 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false 
-Djboss.platform.mbeanserver 
-Djavax.management.builder.initial=org.jboss.system.server.jmx.MBeanServerBuilderImpl 
-DJBOSS_CLASSPATH="../lib/jboss-system-jmx.jar" 

然後你就可以看到的java.lang在此設置下:類加載MBean並可以減少它的開/關的飛行。如果您只在執行某段代碼時需要它,這很有幫助。

還有一個MBean,它將允許您輸入完全限定的類名並查看它從類層次結構中加載的位置。 MBean被稱爲LoaderRepository,您需要調用displayClassInfo()操作,傳入FQCN。

0

在WebSphere(WAS),你可以使用一種叫做「類裝入器查看器」

功能通過單擊服務器>服務器類型> WebSphere應用程序服務器>服務器名稱>類裝入器查看器服務第一啓用類裝入器查看器,啓用服務並重新啓動服務器。

然後,您可以轉到故障排除>類加載器查看器並搜索您的類或包名稱。

https://www-01.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd.doc/ae/ttrb_classload_viewer.html?lang=en

0

您可以輕鬆地導出JMX操作來訪問包信息的任何加載的類在您處理,如:

public static final class Jmx { 

    @JmxExport 
    public static Reflections.PackageInfo getPackageInfo(@JmxExport("className") final String className) { 
     return Reflections.getPackageInfo(className); 
    } 
    } 

,這裏是一個簡單的單元測試導出並調用它:

@Test 
    public void testClassLocator() throws IOException, InstanceNotFoundException, MBeanException, ReflectionException { 
    Registry.export(Jmx.class); 
    Reflections.PackageInfo info = (Reflections.PackageInfo) Client.callOperation(
      "service:jmx:rmi:///jndi/rmi://:9999/jmxrmi", 
      Jmx.class.getPackage().getName(), 
      Jmx.class.getSimpleName(), "getPackageInfo", Registry.class.getName()); 
    System.out.println(info); 
    Assert.assertNotNull(info); 
    } 

這是所有基於利用spf4j(http://www.spf4j.org

一些小實用工具庫

你可以看到這個代碼at和測試at