使用Java代理修改已加载的类?

问题描述 投票:4回答:2

目前我正在尝试修改驻留在JVM已经加载的类中的方法体。我知道JVM实际上不允许更改已经加载的类的定义。但是我的研究使我得到了像JRebel或Java Instrumentation API这样的实现,两者都使用了基于代理的方法。我知道如何在代表Javassist加载类之前做到这一点。但考虑到例如在应用程序启动时加载类定义的EJB环境中的JRebel,不应该在加载JVM的类上进行字节码修改吗?

java bytecode javaagents jrebel
2个回答
6
投票

好吧,你了解到Instrumentation API存在并且它提供redefinition of classes作为操作。那么现在是时候重新考虑“JVM实际上不允许更改已经加载的类的定义”的初始前提。

你应该注意到这一点

  • 如链接所示,Instrumentation API是标准API的一部分
  • 然而,重新定义类的支持是可选的。您可以ask当前JVM是否支持此功能
  • 它可能仅限于不支持每个班级;你可能会问whether it’s possible for a particular class
  • 引用the documentation时,即使它受到支持,更改也可能有限。 重新定义可以改变方法体,常量池和属性。重定义不得添加,删除或重命名字段或方法,更改方法的签名或更改继承。在将来的版本中可能会取消这些限制。
  • 在执行重新定义时,可能会有线程执行这些类的方法代码;这些执行将使用旧代码完成

因此,Instrumentation仅用于调试和分析等。

但是其他框架,比如EJB容器,在生产代码中提供类重新加载,通常需要创建新的ClassLoaders,它们创建不同版本的类,然后完全独立于旧版本。

在Java运行时环境中,类的标识由一对<ClassLoader, Qualified Name>组成,而不仅仅是一个限定名称...


2
投票

我不知道您可以使用instrumentation API来重新定义类(请参阅@ Holger的答案)。但是,正如他所指出的那样,这种方法存在一些重大限制。此外,javadoc说:

“此方法适用于仪器,如类规范中所述。”

使用它来实质上改变类的语义是......从Java类型系统的角度来看各种各样的错误。

© www.soinside.com 2019 - 2024. All rights reserved.