|
JavaTM Platform Standard Ed. 6 |
|||||||||
上一个类 下一个类 | 框架 无框架 | |||||||||
摘要: 嵌套 | 字段 | 构造方法 | 方法 | 详细信息: 字段 | 构造方法 | 方法 |
public interface Instrumentation
此类提供检测 Java 编程语言代码所需的服务。检测是向方法中添加字节码,以搜集各种工具所使用的数据。由于更改完全是进行添加,所以这些工具不修改应用程序的状态或行为。这种无害工具的例子包括镜像代理、分析器、覆盖分析器和事件记录器。
获取 Instrumentation
接口的实例有两种方式:
当 JVM 以指示一个代理类的方式启动时,将传递给代理类的 premain
方法一个 Instrumentation
实例。
当 JVM 提供某种机制在 JVM 启动之后某一时刻启动代理时,将传递给代理代码的 agentmain
方法一个 Instrumentation
实例。
这些机制在包规范中描述。
如果某个代理获得了 Instrumentation
实例,它便可以在任何时候调用该实例上的方法。
方法摘要 | |
---|---|
void |
addTransformer(ClassFileTransformer transformer) 注册提供的转换器。 |
void |
addTransformer(ClassFileTransformer transformer, boolean canRetransform) 注册提供的转换器。 |
void |
appendToBootstrapClassLoaderSearch(JarFile jarfile) 指定 JAR 文件,检测类由引导类加载器定义。 |
void |
appendToSystemClassLoaderSearch(JarFile jarfile) 指定 JAR 文件,检测类由系统类加载器定义。 |
Class[] |
getAllLoadedClasses() 返回 JVM 当前加载的所有类的数组。 |
Class[] |
getInitiatedClasses(ClassLoader loader) 返回所有初始化加载器是 loader 的类的数组。 |
long |
getObjectSize(Object objectToSize) 返回指定对象使用的特定于实现的近似存储量。 |
boolean |
isModifiableClass(Class<?> theClass) 确定一个类是否可以被 retransformation 或 redefinition 修改。 |
boolean |
isNativeMethodPrefixSupported() 返回当前 JVM 配置是否支持设置本机方法前缀。 |
boolean |
isRedefineClassesSupported() 返回当前 JVM 配置是否支持类的重定义。 |
boolean |
isRetransformClassesSupported() 返回当前 JVM 配置是否支持类的重转换。 |
void |
redefineClasses(ClassDefinition... definitions) 使用提供的类文件重定义提供的类集。 |
boolean |
removeTransformer(ClassFileTransformer transformer) 注销提供的转换器。 |
void |
retransformClasses(Class<?>... classes) 重转换提供的类集。 |
void |
setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) 通过允许重试,将前缀应用到名称,此方法修改本机方法解析的失败处理。 |
方法详细信息 |
---|
void addTransformer(ClassFileTransformer transformer, boolean canRetransform)
canRetransform
为 true,那么
重转换类时也将调用该转换器。 有关转换调用的顺序,请参见
ClassFileTransformer.transform
。 如果转换器在执行过程中抛出异常,JVM 将仍然按顺序调用其他已注册转换器。可以多次添加相同的转换器,但建议最好创建一个新的转换器类实例来避免这样做。
此方法旨在用于检测,正如类规范所述。
transformer
- 要注册的转换器
canRetransform
- 此转换器的转换是否可以重转换
NullPointerException
- 如果传递了
null
转换器
UnsupportedOperationException
- 如果
canRetransform
为 true 但当前 JVM 的配置不允许重转换(
isRetransformClassesSupported()
为 false)。
void addTransformer(ClassFileTransformer transformer)
与 addTransformer(transformer, false)
相同。
transformer
- 要注册的转换器
NullPointerException
- 如果传递了一个
null
转换器
addTransformer(ClassFileTransformer,boolean)
boolean removeTransformer(ClassFileTransformer transformer)
transformer
- 要注销的转换器
NullPointerException
- 如果传递了一个
null
转换器
boolean isRetransformClassesSupported()
Can-Retransform-Classes
清单属性在代理 JAR 文件中设置为
true
(如
包规范所述),且 JVM 支持此性能时,才支持重转换。 在单个 JVM 的单个实例化过程中,多次调用此方法将总是返回相同的答案。
retransformClasses(java.lang.Class
...)
void retransformClasses(Class<?>... classes) throws UnmodifiableClassException
此函数为检测已加载类提供了方便。 当最初加载了类或重定义了类时,初始类文件字节可以使用 ClassFileTransformer
转换。 此函数返回转换进程(以前是否发生过转换)。 此转换按以下步骤进行:
canRetransform
设为 false 的转换器,上一次类加载或重定义期间 transform
返回的字节将被重新用于转换的输出;注意,这等价于不做更改地重新应用前一个转换;没有调用 transform
的情况除外。 canRetransform
设为 true 的转换器,在这些转换器中调用 transform
方法 转换的顺序在 transform
方法中描述。在自动重新应用不可重转换的转换时,也将使用这一顺序。
最初的类文件字节表示(应用转换前)传递给 ClassLoader.defineClass
或 redefineClasses
的字节,但有可能不完全匹配。常量池的布局或内容可能不同。常量池的条目可能多一些或少一些。常量池条目的顺序可能不同,但是,方法字节码中常量池的索引将是对应的。一些属性可能不存在。在顺序没有意义的地方(例如,方法的顺序),可能不保留顺序。
此方法在一个集合上操作,以便允许同时对多个类进行相互依赖的更改(重转换类 A 要求重转换类 B)。
如果重转换的方法有活动的堆栈帧,那么这些活动的帧将继续运行原方法的字节码。重转换的方法将用于新的调用。
此方法不会引起任何初始化操作,JVM 惯例语义下发生的初始化除外。换句话说,重定义一个类不会引起其初始化方法的运行。静态变量的值将与调用之前的值一样。
重转换类的实例不受影响。
重转换可能会更改方法体、常量池和属性。重转换不得添加、移除、重命名字段或方法;不得更改方法签名、继承关系。在以后的版本中,可能会取消这些限制。在应用转换之前,类文件字节不会被检查、验证和安装。如果结果字节错误,此方法将抛出异常。
如果此方法抛出异常,则不会重转换任何类。
此方法旨在用于检测,正如类规范所述。
classes
- 要转换的类数组; 允许长度为 0 数组,在这种情况下,此方法不执行任何操作
UnmodifiableClassException
- 如果不能修改指定的类(
isModifiableClass(java.lang.Class
)
返回
false
)
UnsupportedOperationException
- 如果 JVM 的当前配置不允许重转换(
isRetransformClassesSupported()
为 false),或者重转换试图做出不受支持的更改
ClassFormatError
- 如果数据不包含有效的类
NoClassDefFoundError
- 如果类文件中的名称不等于类的名称
UnsupportedClassVersionError
- 如果类文件版本号不受支持
ClassCircularityError
- 如果新类包含循环
LinkageError
- 如果发生链接错误
NullPointerException
- 如果提供的类数组或其任意组件为
null
。
isRetransformClassesSupported()
,
addTransformer(java.lang.instrument.ClassFileTransformer, boolean)
,
ClassFileTransformer
boolean isRedefineClassesSupported()
Can-Retransform-Classes
清单属性在代理 JAR 文件中设置为
true
(如
包规范所述),且 JVM 支持此性能时,才支持重转换。 在执行单个 JVM 的单实例化过程中,对此方法的多次调用将始终返回同一应答。
redefineClasses(java.lang.instrument.ClassDefinition...)
void redefineClasses(ClassDefinition... definitions) throws ClassNotFoundException, UnmodifiableClassException
此方法用于替代类的定义,而不引用现有的类文件字节,这与 fix-and-continue 调试过程中重新编译源代码时所做的一样。需要转换现有类文件字节的地方(例如,字节码检测中)应该使用 retransformClasses
。
此方法在一个集合上操作,以便允许同时对多个类进行相互依赖的更改(重定义类 A 要求重定义类 B)。
如果重定义的方法有活动的堆栈帧,那么这些活动的帧将继续运行原方法的字节码。将在新的调用上使用此重定义的方法。
此方法不会引起任何初始化操作,JVM 惯例语义下发生的初始化除外。换句话说,重定义一个类不会引起其初始化方法的运行。静态变量的值将与调用之前的值一样。
重定义类的实例不受影响。
重定义可能会更改方法体、常量池和属性。重定义不得添加、移除、重命名字段或方法;不得更改方法签名、继承关系。在以后的版本中,可能会取消这些限制。在应用转换之前,类文件字节不会被检查、验证和安装。如果结果字节错误,此方法将抛出异常。
如果此方法抛出异常,则不会重定义任何类。
此方法旨在用于检测,正如类规范所述。
definitions
- 要使用相应定义来进行重定义的类数组;允许长度为 0 数组,在这种情况下,此方法不执行任何操作
UnmodifiableClassException
- 如果无法修改指定的类(
isModifiableClass(java.lang.Class
)
返回
false
)
UnsupportedOperationException
- 如果 JVM 的当前配置不允许重定义(
isRedefineClassesSupported()
为 false)或重定义试图做出不受支持的更改
ClassFormatError
- 如果数据不包含有效类
NoClassDefFoundError
- 如果类文件中的名称与类名称不相等
UnsupportedClassVersionError
- 如果类文件版本号不受支持
ClassCircularityError
- 如果新类包含循环
LinkageError
- 如果发生链接错误
NullPointerException
- 如果提供的定义数组或其任何组件为
null
。
ClassNotFoundException
- 不会抛出(存在只是为了兼容)
isRedefineClassesSupported()
,
addTransformer(java.lang.instrument.ClassFileTransformer, boolean)
,
ClassFileTransformer
boolean isModifiableClass(Class<?> theClass)
true
。 如果类不能被修改,那么此方法返回
false
。
对于要重转换的类,isRetransformClassesSupported()
也必须为 true。但 isRetransformClassesSupported()
的值不影响此函数返回的值。 对于要重定义的类,isRedefineClassesSupported()
也必须为 true。但 isRedefineClassesSupported()
的值不影响此函数返回的值。
基本类(例如 java.lang.Integer.TYPE
)和数组类不可修改。
NullPointerException
- 如果指定的类为
null
。
retransformClasses(java.lang.Class
...)
,
isRetransformClassesSupported()
,
redefineClasses(java.lang.instrument.ClassDefinition...)
,
isRedefineClassesSupported()
Class[] getAllLoadedClasses()
Class[] getInitiatedClasses(ClassLoader loader)
loader
的类的数组。如果提供的加载器为
null
,则返回由引导类加载器初始化的类。
loader
- 将返回其初始化类列表的加载器
loader
的类的数组;如果没有,则返回长度为 0 数组
long getObjectSize(Object objectToSize)
objectToSize
- 需要确定大小的对象
NullPointerException
- 如果提供的 Object 为
null
。
void appendToBootstrapClassLoaderSearch(JarFile jarfile)
当虚拟机的内置类加载器(称为“引导类加载器”)未能成功搜索到类时,JAR 文件
中的条目也将被搜索。
可以多次使用此方法,按照调用此方法的顺序添加多个要搜索的 JAR 文件。
除了需要引导类加载器为检测而定义的类或资源外,代理应该注意确保 JAR 不包含任何其他类或资源。 违反此规定将导致难以诊断的不可预料行为。例如,假设有加载器 L,L 的代理父加载器为引导类加载器。 此外,有一个类 C 的方法,有一个 L 定义的类,引用了非公共存取类 C$1。如果 JAR 文件包含类 C$1,那么引导类加载器的代理将导致 C$1 被引导类加载器定义。此例中将抛出 IllegalAccessError
,这可能导致应用程序失败。一个避免这类问题的办法是,对检测类使用唯一的包名称。
Java 虚拟机规范规定,后续尝试解析 Java 虚拟机以前未能成功解析的符号引用将总是失败,并抛出与最初解析尝试失败时相同的错误。因此,如果 JAR 文件包含的某个条目对应于 Java 虚拟机未能成功解析引用的类,那么后续尝试解析该引用将总是失败,并抛出与最初解析尝试失败时相同的错误。
jarfile
- 当引导类加载器未成功搜索到类时要搜索的 JAR 文件。
NullPointerException
- 如果
jarfile
为
null
。
appendToSystemClassLoaderSearch(java.util.jar.JarFile)
,
ClassLoader
,
JarFile
void appendToSystemClassLoaderSearch(JarFile jarfile)
getSystemClassLoader()
)未能成功搜索到类时,
JarFile
中的条目也将被搜索。
可以多次使用此方法,按照调用此方法的顺序添加多个要搜索的 JAR 文件。
除了需要系统类加载器为检测而定义的类或资源外,代理应该注意确保 JAR 不包含任何其他类或资源。 违反此规定将导致难以诊断的不可预料行为。(参见 appendToBootstrapClassLoaderSearch
)。
如果实现了名为 appendToClassPathForInstrumentation
的方法(带有一个类型为 java.lang.String
的参数),那么系统类加载器支持添加要搜索的 JAR 文件。不要求该方法具有 public
访问权。JAR 文件名可以通过对 jarfile
调用 getName()
方法获取,并将作为参数提供给 appendtoClassPathForInstrumentation
方法。
Java 虚拟机规范规定,后续尝试解析 Java 虚拟机以前未能成功解析的符号引用将总是失败,并抛出与最初解析尝试失败时相同的错误。因此,如果 JAR 文件包含的某个条目对应于 Java 虚拟机未能成功解析引用的类,那么后续尝试解析该引用将总是失败,并抛出与最初解析尝试失败时相同的错误。
此方法不更改 java.class.path
系统属性
的值。
jarfile
- 当系统类加载器未成功搜索到类时要搜索的 JAR 文件。
UnsupportedOperationException
- 如果系统类加载器不支持添加要搜索的 JAR 文件。
NullPointerException
- 如果
jarfile
为
null
。
appendToBootstrapClassLoaderSearch(java.util.jar.JarFile)
,
ClassLoader.getSystemClassLoader()
,
JarFile
boolean isNativeMethodPrefixSupported()
Can-Set-Native-Method-Prefix
清单属性在代理 JAR 文件中设置为
true
(如
包规范所述),且 JVM 支持此性能时,才支持设置本机方法前缀。 在单个 JVM 的单个实例化过程中,多次调用此方法将总是返回相同的应答。
setNativeMethodPrefix(java.lang.instrument.ClassFileTransformer, java.lang.String)
void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix)
ClassFileTransformer
一起使用时,它允许检测本机方法。
由于本机方法不能直接检测(它们没有字节码),因此必须使用可以检测的非本机方法包装它们。例如,如果有:
native boolean foo(int x);
那么可以转换类文件(在类的初始定义过程中使用 ClassFileTransformer),使之变成:
boolean foo(int x) { ... record entry to foo ... return wrapped_foo(x); } native boolean wrapped_foo(int x);
其中 foo
变为实际本机方法的包装器,并带有附加前缀 "wrapped_"。注意,将 "wrapped_" 作为前缀并不合适,因为它很有可能与现有方法重名,因此 "$$$MyAgentWrapped$$$_" 之类更加合适,但那将减少这些示例的可读性。
包装器将允许在本机方法调用上收集数据,但现在的问题在于如何连接包装的方法与本机实现。 也就是说,方法 wrapped_foo
需要被解析为 foo
的本机实现,即:
Java_somePackage_someClass_foo(JNIEnv* env, jint x)
此函数允许指定前缀并进行恰当的解析。 明确地说,当标准解析失败时,解析将重新尝试考虑前缀。进行解析有两种方式,使用 JNI 函数 RegisterNatives
的显式解析和常规自动解析。对于 RegisterNatives
,JVM 将尝试以下关联:
method(foo) -> nativeImplementation(foo)
若此操作失败,解析将重试,将指定的前缀添加到方法名,生成校正解析:
method(wrapped_foo) -> nativeImplementation(foo)
对于自动解析,JVM 将尝试:
method(wrapped_foo) -> nativeImplementation(wrapped_foo)
若此操作失败,解析将重试,从实现名删除指定的前缀,生成校正解析:
method(wrapped_foo) -> nativeImplementation(foo)
注意,前缀只在标准解析失败时使用,因此可以有选择地包装本机方法。
每个 ClassFileTransformer
可以执行其本身的字节代码转换,因此可能要应用多个包装器层。所以每个转换器需要其自己的前缀。转换是按顺序应用的,因此前缀(如果应用)也将按相同的顺序应用(参见 addTransformer
)。 所以,如果三个转换器应用了包装器,foo
将变为 $trans3_$trans2_$trans1_foo
。但是,如果第二个转换器没有对 foo
应用包装器,那么它将是 $trans3_$trans1_foo
。要有效的确定前缀序列,仅当其非本机包装器存在时才应用中间前缀。因此,在最后一个示例中,即使 $trans1_foo
不是本机方法,$trans1_
前缀也将应用,因为 $trans1_foo
存在。
transformer
- 使用此前缀包装的 ClassFileTransformer。
prefix
- 已应用到包装的本机方法的前缀。
NullPointerException
- 如果传入
null
转换器。
UnsupportedOperationException
- 如果 JVM 的当前配置不允许设置本机方法前缀(
isNativeMethodPrefixSupported()
为 false)。
IllegalArgumentException
- 如果转换器没有注册(参见
addTransformer
)。
|
JavaTM Platform Standard Ed. 6 |
|||||||||
上一个类 下一个类 | 框架 无框架 | |||||||||
摘要: 嵌套 | 字段 | 构造方法 | 方法 | 详细信息: 字段 | 构造方法 | 方法 |
版权所有 2007 Sun Microsystems, Inc. 保留所有权利。 请遵守许可证条款。另请参阅文档重新分发政策。