在 WildFly 8 上检测 webapp 时出现 VerifyError

VerifyError when instrumenting webapp on WildFly 8

我目前正在处理一个项目,试图将额外的 Log4j 日志记录语句插入 运行 webapp。为了意识到这一点,我通过以下方式启动了一个 Java 代理 启动 WildFly 时的 JVM 参数:

-javaagent:path/to/agent.jar

代理的 premain 方法接收 Instrumentation 对象并建立用于远程访问的 MBean。日志记录插入是使用 Instrumentation 和 Javassist 实现的。到目前为止,这很完美。 然而,为了保持它的工作,agent.jar 还必须在部署时驻留在 webapp 的 WAR 文件中,因为用于日志记录的 log4j Logger class 随此 JAR 一起提供。如果不是,当 Instrumentation API 更新 class 定义时,我会得到一个 VerifyError。但是试图加载例如classes from java.lang 通过插入类似 "Math.random()" 的代码按预期工作。
请务必注意,代理 classes 加载了 AppClassLoader,它也是应用程序 ModuleClassLoader 的父级。 因此我想知道为什么驻留在 agent.jar 中的 classes 不能通过 ModuleClassLoader 委托加载。 这些观察使我假设 webapp 模块需要声明对外部 JAR 的显式依赖,即使 classes 为父 AppClassLoader 所知。对于安全问题,这对我来说很有意义。

任何人都可以证实这些假设,或者是否有人有其他想法或经历是什么导致了这种行为?

谢谢!

----------------编辑--------------------

使用 WildFly class加载机制帮助我更详细地描述了我的问题。假设我想使用属于我的 webapp 的 ManagedBean 中的 ModuleClassLoader 加载一个名为 com.example.LoggerClass(位于 agent.jar!)的 class:

Class<?> aClass = this.getClass().getClassLoader().loadClass("com.example.LoggerClass");

这会导致 ClassNotFoundException! 但是手动将它委托给底层的 AppClassLoader 是完美的:

Class<?> aClass = this.getClass().getClassLoader().getParent().loadClass("com.example.LoggerClass");

现在 JBoss 有关 ModuleClassLoader 的 loadClass 方法的文档说明如下:

找一个class,可能委托给其他装载机

这可以解释我在上面显示的行为,假设 ModuleClassLoader 由于安全问题不委托 class 加载。在某些情况下,有什么方法可以覆盖它并使 ModuleClassLoader 委托给 AppClassLoader 吗?

Java 代理总是由系统 class 加载器加载。它的所有依赖项都必须在 class 路径上可用。如果您遇到验证器错误,则您的字节码是非法的,因为验证发生在加载完成之前。这意味着,您的问题与 class 加载程序无关。