我正在试验ASM 4.0,但在运行代理时遇到了一些问题。我有一个TraceTransformer
应该转换字节码的类,但是出了点问题——当我尝试转换它时,似乎我访问的每个类都被破坏了。
代理人
JavaTraceAgent.java:
package traceagent;
import java.lang.instrument.Instrumentation;
public class JavaTraceAgent {
private static Instrumentation instrumentation;
private static String agentId = "Uninitialized";
public static void premain(String args, Instrumentation inst) throws Exception {
instrumentation = inst;
instrumentation.addTransformer(new TraceTransformer());
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
instrumentation = inst;
instrumentation.addTransformer(new TraceTransformer());
}
public static void initialize() {
if (instrumentation == null) {
JavaAgentLoader.loadAgent();
}
}
public static void logMethodInvocation() {
System.out.println("Logging invocation...");
//Thread.dumpStack();
System.out.println("logging complete!");
}
public static void setAgentId(String _agentId) {
agentId = _agentId;
}
}
TraceTransformer.java
package traceagent;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
public class TraceTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if (!className.contains("superman")) return classfileBuffer;
System.out.println("TraceTransformer invoked on " + className);
ClassReader reader = new ClassReader(classfileBuffer);
ClassWriter writer = new ClassWriter(reader, 0);
ClassVisitor visitor = new ClassVisitor(Opcodes.ASM4, writer) {
@Override
public MethodVisitor visitMethod(int access, final String name, String desc, String signature, String[] exceptions) {
return new MethodVisitor(Opcodes.ASM4) {
@Override
public void visitCode() {
if (name.contains("sayHello")) {
super.visitMethodInsn(Opcodes.INVOKESTATIC, "traceagent/JavaTraceAgent", "logMethodInvocation", "()V");
System.out.println("Injecting logger on " + name);
}
super.visitCode();
}
};
}
};
reader.accept(visitor, 0);
return writer.toByteArray();
}
}
显现
构建.xml:
... <清单> <attribute name="Built-By" value="${user.name}"/> <attribute name="Class-Path" value="${manifest.classpath}"/> <attribute name="Agent-Class" value="traceagent.JavaTraceAgent" /> <attribute name="Can-Redefine-Classes" value="true" /> <attribute name="Can-Retransform-Classes" value="true" /> <attribute name="Premain-Class" value="traceagent.JavaTraceAgent" /> </清单> ...
目标
Program.java (入口点):
package jack;
import jack.superman.Hello;
public class Program {
/**
* @param args
*/
public static void main(String[] args) {
Hello.sayHello();
}
}
你好.java:
package jack.superman;
public class Hello {
public static void sayHello() {
System.out.println("Hello");
}
}
目前的程序
...\src> javac -d . jack\Program.java
...\src> java --javagent:jack\TAgent.jar jack.Program
TraceTransformer invoked on jack/superman/Hello
Injecting logger on sayHello
Exception in thread "main" java.lang.NoSuchMethodError: jack.superman.Hello.sayHello()V
at jack.Program.main(Program.java:10)
我在这里做错了什么?如何避免“破坏”该方法?