Module java.instrument

Interface ClassFileTransformer


public interface ClassFileTransformer
一个类文件的转换器。代理通过使用addTransformer方法注册此接口的实现,以便在加载类时调用转换器的transform方法,或者在类被重新定义重新转换时调用。实现应该覆盖这里定义的transform方法之一。转换器在Java虚拟机定义类之前被调用。

有两种类型的转换器,由Instrumentation.addTransformer(ClassFileTransformer,boolean)canRetransform参数确定:

一旦转换器已经注册到addTransformer,该转换器将在每个新类定义和每个类重新定义时被调用。可重新转换的转换器还将在每个类重新转换时被调用。请求新类定义使用ClassLoader.defineClass或其本机等效方法。请求类重新定义使用Instrumentation.redefineClasses或其本机等效方法。请求类重新转换使用Instrumentation.retransformClasses或其本机等效方法。在处理请求期间,转换器在类文件字节被验证或应用之前被调用。当存在多个转换器时,通过链接transform调用来组合转换。也就是说,一个transform调用返回的字节数组将成为下一个调用的输入(通过classfileBuffer参数)。

转换按以下顺序应用:

  • 不可重新转换的转换器
  • 不可重新转换的本机转换器
  • 可重新转换的转换器
  • 可重新转换的本机转换器

对于重新转换,不会调用不可重新转换的转换器,而是重用先前转换的结果。在所有其他情况下,将调用此方法。在这些分组中,按注册顺序调用转换器。本机转换器由Java虚拟机工具接口中的ClassFileLoadHook事件提供)。

第一个转换器的输入(通过classfileBuffer参数)是:

  • 对于新类定义,传递给ClassLoader.defineClass的字节
  • 对于类重新定义,definitionsInstrumentation.redefineClasses的参数,其中definitions.getDefinitionClassFile()
  • 对于类重新转换,传递给新类定义的字节或者如果重新定义,则是最后一次重新定义的字节,所有不可重新转换的转换器所做的所有转换将自动重新应用且不变;有关详细信息,请参见Instrumentation.retransformClasses

如果实现方法确定不需要进行任何转换,则应返回null。否则,应创建一个新的byte[]数组,将输入classfileBuffer及所有所需的转换复制到其中,并返回新数组。输入classfileBuffer不得被修改。

在重新转换和重新定义情况下,转换器必须支持重新定义语义:如果转换器在初始定义期间更改的类稍后被重新转换或重新定义,则转换器必须确保第二个输出类文件是第一个输出类文件的合法重新定义。

如果转换器抛出异常(它不捕获),后续转换器仍将被调用,并且加载、重新定义或重新转换仍将尝试。因此,抛出异常的效果与返回null相同。为防止在转换器代码中生成未经检查的异常时出现意外行为,转换器可以捕获Throwable。如果转换器认为classFileBuffer不代表格式正确的类文件,则应抛出IllegalClassFormatException;虽然这与返回null的效果相同,但它有助于记录或调试格式损坏。

请注意,术语类文件Java虚拟机规范第3.1节中定义的那样使用,表示类文件格式中的字节序列,无论它们是否驻留在文件中。

自版本:
1.5
参见:
  • Method Summary

    Modifier and Type
    Method
    Description
    default byte[]
    transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)
    转换给定的类文件并返回一个新的替换类文件。
    default byte[]
    transform(Module module, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)
    转换给定的类文件并返回一个新的替换类文件。
  • Method Details

    • transform

      default byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException
      转换给定的类文件并返回一个新的替换类文件。当未覆盖带有transformModule时,将调用此方法。
      实现要求:
      默认实现返回null。
      参数:
      loader - 要转换的类的定义加载器,如果是引导加载器,则可以为null
      className - 类的名称,以Java虚拟机规范中定义的完全限定类和接口名称的内部形式表示。例如,"java/util/List"
      classBeingRedefined - 如果这是由重新定义或重新转换触发的,则为正在重新定义或重新转换的类;如果这是类加载,则为null
      protectionDomain - 正在定义或重新定义的类的保护域
      classfileBuffer - 类文件格式中的输入字节缓冲区 - 不得修改
      返回:
      一个格式良好的类文件缓冲区(转换的结果),如果未执行任何转换,则返回null
      抛出:
      IllegalClassFormatException - 如果输入不代表格式良好的类文件
    • transform

      default byte[] transform(Module module, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException
      转换给定的类文件并返回一个新的替换类文件。
      实现要求:
      此方法的默认实现调用transform方法。
      参数:
      module - 要转换的类的模块
      loader - 要转换的类的定义加载器,如果是引导加载器,则可以为null
      className - 类的名称,以Java虚拟机规范中定义的完全限定类和接口名称的内部形式表示。例如,"java/util/List"
      classBeingRedefined - 如果这是由重新定义或重新转换触发的,则为正在重新定义或重新转换的类;如果这是类加载,则为null
      protectionDomain - 正在定义或重新定义的类的保护域
      classfileBuffer - 类文件格式中的输入字节缓冲区 - 不得修改
      返回:
      一个格式良好的类文件缓冲区(转换的结果),如果未执行任何转换,则返回null
      抛出:
      IllegalClassFormatException - 如果输入不代表格式良好的类文件
      自版本:
      9