我的理解是,如果我使用:
Instrumentation#getAllLoadedClasses()
我确实选择了目标 JVM 加载的所有类。但如果我这样做:
Class.forName("my.class.name")
这与 VM 加载的类不是同一个类。是的,我可以将这个特定的类作为 jar 添加到代理 MANIFEST.MF 类路径中 - 但这对我来说与 getAllLoadedClasses()
不同。
有人可以确认这是否正确,即我在检测时无法使用 Class.forName()
找到特定的类吗?我的目标不是使用 getAllLoadedClasses()
迭代所有加载的类 - 但如果没有其他选择,我想现在就可以了。
** 更新
我在编写时犯的错误是 Boot-Class-Path
,我现在已在 list 中更正了该错误。使用 -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。
进一步更新
好吧,我已经“加肥”了 list ,以查找我的 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
目录的所有类。我还可以确认加载器正确地看到了 jar。
4) 现在我注入(inject)代理,并从代理类中调用 Class.forName("my.pkg.MyClass")
。我得到以下结果。
[Loaded my.pkg.MyClass from file:/C:/base/webapps/ROOT/WEB-INF/lib/mypkg.jar]
我承认它是系统类加载器将其加载到我的代理代码中,正如 @RafaelWinterhalter 在他的一个答案中指出的那样。有什么方法可以强制“委托(delegate)”,以便不同的类加载器加载代理类,从而正确地重新定义类。
感谢任何帮助。
最佳答案
正如 javadoc 中所述:
Invoking this method is equivalent to:
Class.forName(className, true, currentLoader)
wherecurrentLoader
denotes the defining class loader of the current class.
从源代码中还可以看到,该方法被标记为@CallerSensitive
,这意味着根据调用该方法的类加载器,您会得到不同的结果。
当调用Instrumentation::getAllLoadedClasses
时,返回的数组包含任何类加载器的类,而不仅仅是当前类加载器(运行Java代理时是系统类加载器)的类。因此:
for (Class<?> type : instrumentation.getAllLoadedClasses()) {
assert type == Class.forName(type.getName());
}
通常情况下并不正确。
关于java - 在 Java Instrumentation Agent 中使用 Class.forName(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46523055/