2009-06-03 92 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