使用自定义Java代理打包jar文件时,可以添加以下属性:
Can-Redefine-ClassesCan-Retransform-Classes这两者有什么区别?
如果重新定义发生在类加载和重新转换之后,那么何时发生了完全重新转换?
它们为我们提供的功能似乎几乎是多余的.主要区别似乎是当我们重新定义一个类时,我们提供了一个byte[]新的定义,而当我们重新转换时,我们byte[]通过相同的API 得到一个包含当前定义,并返回一个修改过的byte[].
因此,要重新定义,我们需要更多地了解该课程.考虑注入性能分析跟踪语句的用例.使用重新转换,您可以更直接地执行此操作:只需查看给定的字节码,修改它并返回它.但是如果我们去了重新定义的路线,我们需要byte[]从某个地方(如getResourceAsStream())获取原始内容.
另一个明显的区别在于我们如何与其他类变压器互动; 谁先走了 例如,变换应用于原始类或重新定义的类,因此可以添加多个变换.
从历史上看,如果我们看由于中评论API文档,或238页的这本书(弗里森2007年开始的Java SE 6平台),我们注意到,重新定义功能在Java 5中进行了介绍,并重新转换中的Java 6我的猜测是否将重新转换作为更一般的功能引入,但必须保留重新定义以实现向后兼容性.
从上面链接的书中引用关于重新转换方法的关键句子:
代理使用这些方法重新转换以前加载的类,而无需访问其类文件.
问题的第二部分:
如果重新定义发生在类加载和重新转换之后,那么何时发生了完全重新转换?
不,重载定义在加载类之后发生,以及重新转换.它们分别在您调用Instrumentation实例redefineClasses(..)和retransformClasses(..)方法时发生.
对于任何经过专家的专家来说,这是一个问题:你可以通过重新定义类来做任何事情,通过重新转换它们是不能做到的?我的猜测是答案是"没有".
小智 6
重新定义意味着代理将在任意时间调用工具。redefineClasses更改现有(和已加载)类的实际定义。代理将提供新定义的字节码。
重新转换是指类文件转换的过程,通常在类加载时应用。代理可以注册一个ClassFileTransformers,一个接一个地调用,以便在初始化类之前对字节码进行转换。因此,重新转换是指JVM对已加载的类重复此过程的能力。在这种情况下,代理可以调用Instrumentation.retransformClasses来指定要重新转换的类,但不指定字节码。取而代之的是,JVM将调用所有注册的具有重转换能力的ClassFileTransformers,以提供实际的字节码(或以前的转换程序的结果,用于链接的转换程序)。