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

时间:2015-04-27 08:55:57

标签: java bytecode javaagents jrebel

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

2 个答案:

答案 0 :(得分:6)

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

你应该注意到

  • 如链接所示,Instrumentation API是标准API的一部分
  • 然而,重新定义类的支持是可选的。您可以ask当前JVM是否支持此功能
  • 它可能仅限于不支持每个班级;你可以问whether it’s possible for a particular class
  • 即使支持,但更改可能会受到限制,引用the documentation

      

    重新定义可能会更改方法体,常量池和属性。重定义不得添加,删除或重命名字段或方法,更改方法的签名或更改继承。在将来的版本中可能会取消这些限制。

  •   
  • 在执行重新定义时,可能会有线程执行这些类的方法代码;这些执行将使用旧代码
  • 完成   

     

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

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

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

答案 1 :(得分:2)

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

  

&#34;此方法适用于检测,如类规范中所述。&#34;

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