【发布时间】:2017-10-02 09:38:31
【问题描述】:
我的理解是,如果我使用:
Instrumentation#getAllLoadedClasses()
我确实选择了目标 JVM 加载的所有类。但如果我这样做:
Class.forName("my.class.name")
这将与 VM 加载的类不同。是的,我可以将这个特定的类添加为代理 MANIFEST.MF 类路径中的 jar - 但在我看来这与 getAllLoadedClasses() 不同。
有人可以确认这是否正确,即我在检测时无法使用Class.forName() 找到特定的类?我的目标不是使用 getAllLoadedClasses() 遍历所有加载的类 - 但如果没有其他选择,我想现在还可以。
** 更新
我写的错误是Boot-Class-Path,我现在在我的清单中更正了它。使用 -verbose:class 日志记录我设法看到我的 jar 被加载为
[Opened C:\fullpath\someother.jar]
[Opened C:\fullpath\another.jar]
[Opened C:\fullpath\different.jar]
但我没有看到任何相应的加载信息。我尝试添加 Class.forName("a.package.in.someother.jar.classname") 并得到 NoClassDefFoundError。一旦我跳入代理 jar,我就无法使用 Class.forName() 检查目标 VM 是否加载了该类。我收到 NoClassDefFoundError。
进一步更新
好的,我已经“增肥”了清单,以便在我的 WEB-INF/lib 和 tomcat 的 lib 目录中查找所有类。我可以看到如下:
1) 当我的自定义类 MyClass 第一次加载时。 -verbose 显示:
[Loaded my.pkg.MyClass from file:/C:/base/webapps/ROOT/WEB-INF/lib/mypkg.jar]
2) 如果我再次尝试加载该类,它会正确显示上述顺序。
3) 我的代理 jar 包含我的 tomcat lib 和我的 web-inf/lib 目录的所有类。而且我还可以确认加载程序正确地看到了罐子。
4) 现在我注入代理,并从代理类中调用Class.forName("my.pkg.MyClass")。我得到以下结果。
[Loaded my.pkg.MyClass from file:/C:/base/webapps/ROOT/WEB-INF/lib/mypkg.jar]
我承认,正如@RafaelWinterhalter 在他的一个答案中指出的那样,它是系统类加载器将其加载到我的代理代码中。有什么办法可以强制“委托”,以便不同的类加载器加载代理类,从而正确地重新定义一个类。
感谢任何帮助。
【问题讨论】:
-
是什么让你说
Class.forName("[...]")找到了与Instrumentation.getAllLoadedClasses()不同的类?您的目标类是否没有从正在加载的类中引用? -
@diginoise 我是说根本找不到它们!如果我在注入代理之前加载一个类“my.package.MyClass” - 即使我已将相关 jar 添加到
Boot-Class-Path,代理内部的Class.forName()也看不到相同的类,我可能是错的,但有一个JDK页面上提供的检测信息的根本差距。我在系统中提出了一个错误供他们检查。 -
instrumentation 可以在加载类时观察(和修改)类这一事实并不意味着它的类加载器负责加载这些类。您的应用程序是 Web 应用程序吗?
-
@dignoise 是的,它是一个 web 应用程序,但我相信即使我有一个
helloworld类型的应用程序也会发生这种情况。我想你可能已经从我的脑海中抢走了这个词。解决方案是强制 Instrumentation 使用 VM 的上下文类加载器? -
您可以创建自定义的 ClassLoader 并将其传递给您的 CLASSPATH
标签: java classloader instrumentation