31

有没有办法确定在运行时从哪些 JAR 加载哪些类?

我敢肯定,我们之前都经历过 JAR 地狱。我在项目中遇到过很多故障排除ClassNotFoundException问题NoClassDefFoundError。我想避免在 JAR 中找到一个类的所有实例,并在代码上使用消除过程导致 CNFE 找到罪魁祸首。

任何分析或管理工具会为您提供此类信息吗?

这个问题非常烦人,纯粹是因为我们应该在类被加载时得到这些信息。必须有办法找到它,或者记录下来并找到它,但我不知道会这样做,是吗?

我知道 OSGi 和版本化的包/模块旨在使这成为一个非问题......但它似乎不会很快消失。

注意:我发现这个问题是我与从版本化 jar 加载的类相关的问题的一个子集。

有点相关,这篇文章解释了在 JAR(在当前目录下)或 M2_REPO 中搜索类的策略: JarScan,扫描所有子文件夹中的所有 JAR 文件以查找特定类

也有点相关,JBoss Tattletale

4

5 回答 5

59

-verbose:class将开关传递给java命令将打印每个加载的类以及加载它的位置。

Joops也是一个很好的工具,可以提前找到缺失的课程。

于 2009-06-03T20:59:35.497 回答
15

从代码中您可以调用:

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

(注意,getProtectionDomain可能会不幸返回null(糟糕的设计),因此“正确的代码”会检查这一点。)

于 2009-06-03T21:04:19.310 回答
4

上面 Jason Day 提到的 JVM 标志有一个 MBean。

如果您使用 JBoss,您可以使用 JMX 按需调整它,如果您将本机 JMX MBean 服务器添加到您的配置中。添加以下-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:Classloading MBean 下看到此设置,并可以即时将其打开/关闭。如果您只希望在执行某段代码时打开它,这将很有帮助。

还有一个 MBean,它允许您输入一个完全限定的类名并查看它在类层次结构中的加载位置。MBean 称为 LoaderRepository,您需要调用 displayClassInfo() 操作,传入 FQCN。

于 2010-02-25T21:49:02.770 回答
0

在 WebSphere (WAS) 中,您可以使用称为“类加载器查看器”的功能

首先通过单击服务器 > 服务器类型 > WebSphere 应用程序服务器 > server_name > 类加载器查看器服务启用类加载器查看器,启用该服务并重新启动服务器。

然后您可以转到疑难解答 > 类加载器查看器并搜索您的类或包名称。

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

于 2016-02-10T20:49:59.057 回答
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 )中的一些小型实用程序库

你可以看到这段代码测试

于 2016-04-08T14:17:09.547 回答