目前我正在尝试修改驻留在已由JVM 加载的类中的方法体。我知道JVM实际上不允许更改已经加载的类的定义。但是我的研究使我得到了像JRebel或Java Instrumentation API这样的实现,两者都使用了基于代理的方法。我知道如何在代表Javassist加载类之前做到这一点。但考虑到例如在应用程序启动时加载类定义的EJB环境中的JRebel,不应该在加载JVM的类上进行字节码修改吗?
答案 0 :(得分:6)
嗯,您了解到Instrumentation API存在,并提供redefinition of classes作为操作。那么现在是时候重新考虑“JVM实际上不允许更改已经加载的类的定义”的初始前提。
你应该注意到
重新定义可能会更改方法体,常量池和属性。重定义不得添加,删除或重命名字段或方法,更改方法的签名或更改继承。在将来的版本中可能会取消这些限制。
因此,Instrumentation仅用于调试和分析等。
但是其他框架,比如EJB容器,在生产代码中提供类重新加载,通常需要创建新的ClassLoader
,它们创建不同版本的类,然后完全独立于旧版本。
在Java运行时环境中,类的标识由一对<ClassLoader, Qualified Name>
组成,而不仅仅是一个限定名称......
答案 1 :(得分:2)
我不知道您可以使用instrumentation API重新定义类(请参阅@ Holger的回答)。但是,正如他所指出的那样,这种方法存在一些重大限制。此外,javadoc说:
&#34;此方法适用于检测,如类规范中所述。&#34;
使用它来实质上改变类的语义是......从Java类型系统的角度来看各种各样的错误。