addTransformer
方法注册此接口的实现,以便在加载类时调用转换器的transform
方法,或者在类被重新定义
或重新转换
时调用。实现应该覆盖这里定义的transform
方法之一。转换器在Java虚拟机定义类之前被调用。
有两种类型的转换器,由Instrumentation.addTransformer(ClassFileTransformer,boolean)
的canRetransform
参数确定:
- 可重新转换的转换器,其
canRetransform
为true - 不可重新转换的转换器,其
canRetransform
为false或者使用Instrumentation.addTransformer(ClassFileTransformer)
添加
一旦转换器已经注册到addTransformer
,该转换器将在每个新类定义和每个类重新定义时被调用。可重新转换的转换器还将在每个类重新转换时被调用。请求新类定义使用ClassLoader.defineClass
或其本机等效方法。请求类重新定义使用Instrumentation.redefineClasses
或其本机等效方法。请求类重新转换使用Instrumentation.retransformClasses
或其本机等效方法。在处理请求期间,转换器在类文件字节被验证或应用之前被调用。当存在多个转换器时,通过链接transform
调用来组合转换。也就是说,一个transform
调用返回的字节数组将成为下一个调用的输入(通过classfileBuffer
参数)。
转换按以下顺序应用:
- 不可重新转换的转换器
- 不可重新转换的本机转换器
- 可重新转换的转换器
- 可重新转换的本机转换器
对于重新转换,不会调用不可重新转换的转换器,而是重用先前转换的结果。在所有其他情况下,将调用此方法。在这些分组中,按注册顺序调用转换器。本机转换器由Java虚拟机工具接口中的ClassFileLoadHook
事件提供)。
第一个转换器的输入(通过classfileBuffer
参数)是:
- 对于新类定义,传递给
ClassLoader.defineClass
的字节 - 对于类重新定义,
definitions
是Instrumentation.redefineClasses
的参数,其中definitions.getDefinitionClassFile()
- 对于类重新转换,传递给新类定义的字节或者如果重新定义,则是最后一次重新定义的字节,所有不可重新转换的转换器所做的所有转换将自动重新应用且不变;有关详细信息,请参见
Instrumentation.retransformClasses
如果实现方法确定不需要进行任何转换,则应返回null
。否则,应创建一个新的byte[]
数组,将输入classfileBuffer
及所有所需的转换复制到其中,并返回新数组。输入classfileBuffer
不得被修改。
在重新转换和重新定义情况下,转换器必须支持重新定义语义:如果转换器在初始定义期间更改的类稍后被重新转换或重新定义,则转换器必须确保第二个输出类文件是第一个输出类文件的合法重新定义。
如果转换器抛出异常(它不捕获),后续转换器仍将被调用,并且加载、重新定义或重新转换仍将尝试。因此,抛出异常的效果与返回null
相同。为防止在转换器代码中生成未经检查的异常时出现意外行为,转换器可以捕获Throwable
。如果转换器认为classFileBuffer
不代表格式正确的类文件,则应抛出IllegalClassFormatException
;虽然这与返回null的效果相同,但它有助于记录或调试格式损坏。
请注意,术语类文件如Java虚拟机规范第3.1节中定义的那样使用,表示类文件格式中的字节序列,无论它们是否驻留在文件中。
- 自版本:
- 1.5
- 参见:
-
Method Summary
Modifier and TypeMethodDescriptiondefault 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 - 实现要求:
- 默认实现返回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
-