在我的项目中,我想分两个阶段转换字节码。订单很重要。
例如
String hello()
更改为String hello(String s)
Hello.hello()
更改为Hello.hello("newArgument")
我设法添加变压器,这是第一步。
public class MyJavaAgent {
private static Instrumentation instrumentation;
public static void premain(String args, Instrumentation inst)
throws Exception {
instrumentation = inst;
instrumentation.addTransformer(new MyClassFileTransformer());
}
}
我的问题是:我可以这样添加新的变压器:
public class MyJavaAgent {
private static Instrumentation instrumentation;
public static void premain(String args, Instrumentation inst)
throws Exception {
instrumentation = inst;
instrumentation.addTransformer(new MyClassFileTransformer());
instrumentation.addTransformer(new MyClassFileTransformer2());
}
}
并确保MyClassFileTransformer
在MyClassFileTransformer2
之前完成工作?
答案 0 :(得分:3)
有一种简单的方法可以测试它...在每个Transformer类的transform方法中添加一个System.out指令,该指令将输出各个类的唯一消息。然后查看在控制台上获取输出的顺序。如果在Transformer2之前获得Transformer1的唯一消息,那么是的,按顺序调用转换方法。
这就是我做的......
package Test;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
public class TransFormerTest {
public TransFormerTest() {
super();
}
public static void premain(String agentArguments, Instrumentation instrumentation) {
instrumentation.addTransformer(new Transformer1());
instrumentation.addTransformer(new Transformer2());
}
}
class Transformer1 implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
System.out.println(className + "one"); // one for Transformer
return bytes;
}
}
class Transformer2 implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
System.out.println(className + "two"); // two for Transformer 2
return bytes;
}
}
因此,每次加载一个类并调用变换器时,您应该看到要打印两次的类的名称,首先使用一个作为后缀,然后两个作为后缀。
我用简单的Hello World程序测试了这个理论......这是我的输出::
Test/Transformer2 - one
sun/launcher/LauncherHelper - one
sun/launcher/LauncherHelper - two
java/lang/Enum - one
java/lang/Enum - two
HelloWorld - one
HelloWorld - two
java/lang/Void - one
java/lang/Void - two
Hello World
java/lang/Shutdown - one
java/lang/Shutdown - two
java/lang/Shutdown$Lock - one
java/lang/Shutdown$Lock - two
所以,它似乎确实维持了秩序。
话虽如此,您是否考虑过链接变换方法?例如......
public class TransFormerTest {
public TransFormerTest() {
super();
}
public static void premain(String agentArguments, Instrumentation instrumentation) {
instrumentation.addTransformer(new Transformer());
}
}
class Transformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
byte[] bytes2 = privateTransformer(className, bytes);
return bytes2;
}
private byte[] privateTransformer(String className, byte[] bytes) {
System.out.println(className + " - one");
// TODO add code for First Transformation.
byte[] bytes2 = privateTransformer2(className, bytes);
return bytes2;
}
private byte[] privateTransformer2(String className, byte[] bytes) {
System.out.println(className + " - two");
// TODO add code for Second Transformation.
return bytes;
}
}
这仍然会取得类似的结果,这肯定会保持转变可能发生的顺序。