通过允许重试,将前缀应用到名称,此方法修改本机方法解析的失败处理。
当与 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
)。- 从以下版本开始:
- 1.6