在javaagent中重新定义和重新转换之间的区别

2022-09-04 01:22:34

使用自定义 java 代理打包 jar 文件时,可以添加以下属性:

  • Can-Redefine-Classes
  • Can-Retransform-Classes

这两者之间有什么区别?

如果重定义发生在装入类之前,而重新转换之后,那么重转换究竟是什么时候发生的呢?


答案 1

它们在它们为我们提供的功能中似乎几乎是多余的。主要区别似乎是,当我们重新定义一个类时,我们突然提供了带有新定义的a,而当我们重新转换时,我们通过相同的API获得一个包含当前定义的,并且我们返回一个修改后的。byte[]byte[]byte[]

因此,要重新定义,我们需要更多地了解类。考虑注入分析跟踪语句的用例。通过retransform,您可以更直接地做到这一点:只需查看给定的字节码,修改它,然后返回它。但是,如果我们走重新定义路线,我们将需要从某个地方获取原始内容(例如)。byte[]getResourceAsStream()

另一个明显的区别是我们如何与其他类转换器进行交互;谁先走。变换应用于原始类或重新定义的类,因此多个变换可以是累加的。

从历史上看,如果我们看一下API文档中For注释,或者本书的第238页(Friesen 2007开始Java SE 6平台),我们注意到Java 5中引入了重新定义功能,而Java 6中引入了重新转换。我的猜测是,再转换是作为一种更通用的功能引入的,但是为了向后兼容,必须保留重新定义

引用上面链接的书中关于再转化方法的关键句子:

代理程序使用这些方法重新转换以前装入的类,而无需访问其类文件。


问题的第二部分:

如果重定义发生在装入类之前,而重新转换之后,那么重转换究竟是什么时候发生的呢?

不可以,重定义在类装入后发生,以及重新转换。当您分别调用实例和方法时,会发生这些情况。InstrumentationredefineClasses(..)retransformClasses(..)

这里有一个问题要问任何路过的专家:通过重新定义类,你能做些什么,而通过重新转换它们你无法做到吗?我的猜测是,答案是“没有”。


答案 2

重定义意味着在任意时间点,代理将调用检测。重新定义类以更改现有(和已装入)类的实际定义。代理将为新定义提供字节码。

重转换是指通常在类装入时应用的类文件转换过程。代理可以注册 ClassFileTransformers,这些 Transformers 会依次调用,以便在初始化类之前对字节码应用转换。因此,重新转换是指 JVM 对已装入的类重复此过程的能力。在这种情况下,代理可以调用 Instrumentation.retransformClasses 来指定要重新转换的类,但没有字节码。相反,JVM 将调用所有已注册的具有重新转换功能的 ClassFileTransformers,提供实际的字节码(或链式转换器的上一个转换器的结果)。


推荐