您的要求有點低估。下面是一個示例程序,它使用ASM的訪客API將假設爲具有問題結構的類轉換爲生成的類。我添加了一個方便的方法,接受一個字節數組並返回一個字節數組。在這兩種情況下都可以使用這種方法,即對磁盤上的類文件以及Instrumentation代理應用靜態轉換。
當結合了傳遞給ClassReader
如下一個ClassVisitor
一個ClassWriter
,所以你必須只覆蓋要更改應用這些方法會自動複製源類的所有功能。
這裏,visitMethod
被重寫遇到main
方法時修改它並visitEnd
是重寫,以追加全新showTwo
方法進行攔截。 MainTransformer
將攔截RETURN
指令(在您的示例中應該只有一條),以便將呼叫插入到之前的showTwo
。
import org.objectweb.asm.*;
import org.objectweb.asm.commons.GeneratorAdapter;
public class MyTransformer extends ClassVisitor {
public static byte[] transform(byte[] b) {
final ClassReader classReader = new ClassReader(b);
final ClassWriter cw = new ClassWriter(classReader,
ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
classReader.accept(new MyTransformer(cw), ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
}
public MyTransformer(ClassVisitor cv) {
super(Opcodes.ASM5, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor v=super.visitMethod(access, name, desc, signature, exceptions);
if(name.equals("main") && desc.equals("([Ljava/lang/String;)V"))
v=new MainTransformer(v, access, name, desc, signature, exceptions);
return v;
}
@Override
public void visitEnd() {
appendShowTwo();
super.visitEnd();
}
private void appendShowTwo() {
final MethodVisitor defVisitor = super.visitMethod(
Opcodes.ACC_PUBLIC, "showTwo", "()V", null, null);
defVisitor.visitCode();
defVisitor.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/System", "out", "Ljava/io/PrintStream;");
defVisitor.visitLdcInsn("Show Two Method");
defVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
defVisitor.visitInsn(Opcodes.RETURN);
defVisitor.visitMaxs(0, 0);
defVisitor.visitEnd();
}
class MainTransformer extends GeneratorAdapter
{
MainTransformer(MethodVisitor delegate, int access, String name, String desc,
String signature, String[] exceptions) {
super(Opcodes.ASM5, delegate, access, name, desc);
}
@Override
public void visitInsn(int opcode) {
if(opcode==Opcodes.RETURN) {
// before return insert c.showTwo();
super.visitVarInsn(Opcodes.ALOAD, 1); // variable c
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"ClassName", "showTwo", "()V", false);
}
super.visitInsn(opcode);
}
}
}
@MartinFrank但我想創建一個新的mwthod並調用它。那裏指定的那個在基本水平! – Narayana 2014-08-29 05:37:12
Np。我也會發生。 – icbytes 2014-08-29 07:52:20