Java 如何探索从哪些 JAR 加载哪些类?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/947182/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 21:24:57  来源:igfitidea点击:

How to explore which classes are loaded from which JARs?

javaprofilingclassloaderjar

提问by cwash

Is there a way to determine which classes are loaded from which jars at runtime?

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

I'm sure we've all been in JAR hell before. I've run across this problem a lot troubleshooting ClassNotFoundExceptions and NoClassDefFoundErrors on projects. I'd like to avoid finding all instances of a class in jars and using process of elimination on the code causing a CNFE to find the culprit.

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

Will any profiling or management tools give you this kind of information?

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

This problem is super annoying purely because we should have this information at the time the class gets loaded. There has to be a way to get to it, or record it and find it, yet I know of nothing that will do this, do you?

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

I know OSGi and versioned bundles/modules aim to make this a non issue... but it doesnt seem to be going away any time soon. :)

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

NOTE: I found this questionis a subset of my question related to classes loaded from versioned jars.

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

Update: Somewhat related, this post explains a strategy to search for a class within jars (either under the current directory) or in your M2_REPO. JarScan, scan all JAR files in all subfolders for specific class

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

Update 2: Also somewhat related, JBoss Tattletale

更新 2:也有些相关,JBoss Tattletale

采纳答案by Jason Day

Passing the -verbose:classswitch to the javacommand will print each class loaded and where it was loaded from.

-verbose:classswitch传递给java命令将打印每个加载的类以及它从哪里加载。

Joopsis also a nice tool for finding missing classes ahead of time.

Joops也是一个很好的工具,可以提前查找丢失的类。

回答by Tom Hawtin - tackline

From code you can call:

从代码你可以调用:

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

(Note, getProtectionDomainmay unfortunately return null(bad design), so "proper code" would check for that.)

(注意,getProtectionDomain可能会不幸地返回null(糟糕的设计),所以“正确的代码”会检查它。)

回答by cwash

There is an MBean for the JVM flag mentioned by Jason Day above.

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

If you are using JBoss, you can twiddle this on demand using JMX, if you add the native JMX MBean server to your config. Add the following -D's:

如果您使用 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"

And then you can see this setting under the java.lang:Classloading MBean and can cut it on/off on the fly. This is helpful if you only want it on while executing a certain piece of code.

然后您可以在 java.lang:Classloading MBean 下看到此设置,并可以即时打开/关闭它。如果您只希望在执行某段代码时启用它,这将很有帮助。

There is also an MBean which will allow you to enter a fully qualified classname and see where it was loaded from in the class hierarchy. The MBean is called LoaderRepository and you'll want to invoke the displayClassInfo() operation, passing in the FQCN.

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

回答by cwash

In WebSphere (WAS) you can use a feature called "Class Loader Viewer"

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

Enable the class loader viewer first by clicking Servers > Server Types > WebSphere application servers > server_name > Class loader viewer service, enable the service and restart the server.

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

Then you can go to Troubleshooting > Class Loader Viewer and searching for your class or package name.

然后您可以转到故障排除 > 类加载器查看器并搜索您的类或包名称。

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

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

回答by user2179737

You can easily export a JMX operation to access package info for any loaded class in you process like:

您可以轻松导出 JMX 操作以访问您处理中任何已加载类的包信息,例如:

  public static final class Jmx {

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

and here is a simple unit test to export and invoke it:

这是一个简单的单元测试来导出和调用它:

  @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);
  }

this is all based using some small utilities library from spf4j (http://www.spf4j.org)

这都是基于使用 spf4j ( http://www.spf4j.org) 中的一些小型实用程序库

you can see this code atand the test at

你可以看到这个代码和测试