你有两个解决方案:
1. 使用visitInsn(int opcode)
方法MethodVisitor
:
//this is the custom method visitor
private class InsertInitCodeBeforeReturnMethodVisitor extends MethodVisitor{
public InsertInitCodeBeforeReturnMethodVisitor(MethodVisitor mv) {
super(Opcodes.ASM4, mv);
}
@Override
public void visitInsn(int opcode) {
//whenever we find a RETURN, we instert the code, here only crazy example code
switch(opcode) {
case Opcodes.IRETURN:
case Opcodes.FRETURN:
case Opcodes.ARETURN:
case Opcodes.LRETURN:
case Opcodes.DRETURN:
case Opcodes.RETURN:
mv.visitVarInsn(Opcodes.ALOAD, 42);
break;
default: // do nothing
}
super.visitInsn(opcode);
}
}
2.使用in中的onMethodExit(int opcode)
方法:AdviceAdapter
org.objectweb.asm.commons
//this is the custom method visitor
private class InsertInitCodeBeforeReturnMethodVisitor extends AdviceAdapter{
public InsertInitCodeBeforeReturnMethodVisitor(MethodVisitor mv, int access, String name, String desc) {
super(Opcodes.ASM4, mv, access, name, desc);
}
@Override
protected void onMethodExit(int opcode) {
if(opcode != Opcdoes.ATHROW) {
mv.visitVarInsn(Opcodes.ALOAD, 42);
}
}
}
我个人更喜欢 AdviceAdapter,因为它消除了对原始返回指令进行实际调用的麻烦,就像您对第一个解决方案(例如super.visitInsn(opcode);
)所做的那样。RETURN
其次,它为指令(和)的访问提供了一个很好的抽象ATHORW
;visitInsn(int opcode)
vanilla中的方法并非如此MethodVisitor
,您必须在其中检测访问RETURN
指令以及其他许多指令,例如DUP
sICONST_0
等,这些指令可能与手头的问题相关,也可能不相关。
但这又取决于手头的问题。如果这是唯一正在执行的仪器,我会坚持使用AdviceAdapter
. 如果您想结合参观RETURN
说明做其他事情,我可能会保持简单MethodVisitor
,因为它可能会给我更多的灵活性。话虽这么说,我已经使用AdviceAdapter
了一年多一点的时间来进行一个重型仪器驱动的项目,到目前为止效果很好!
编辑:
应用方法访问者
通常不清楚如何使用或应用方法访问者/方法适配器(至少对我而言),所以我在这里整理了一个快速代码示例:gist.github.com/VijayKrishna/1ca807c952187a7d8c4d,这表明如何使用方法适配器,通过其对应的类访问者/类适配器。在示例代码片段中,我已经更改了我在这个答案中使用的方法适配器的名称,但它们做同样的事情。此外,代码片段显示了一个方法适配器,它扩展了AdviceAdapter
.
总之,您首先“调用”类适配器,如下所示:
ClassReader cr = new ClassReader(in);
ClassWriter cw = new ClassWriter(ClassReader.EXPAND_FRAMES);
ReturnAdapter returnAdapter = new ReturnAdapter(cw, className);
cr.accept(returnAdapter, 0);
然后,您在类适配器的方法中按照以下方式调整visitMethod
方法:
MethodVisitor mv;
mv = cv.visitMethod(access, name, desc, signature, exceptions);
mv = new MethodReturnAdapter(Opcodes.ASM4, className, access, name, desc, mv);
return mv;