上一篇ASM中打印出了被注入函数参数的传入值,[url]http://xkorey.iteye.com/admin/blogs/1667944[/url]
现在将要实现对参数传入值的拦截,不符合判断规则的传入值,将会被直接返回。
实现如下效果:
被拦截的方法是helloWorld中的sayHello
测试代码
注入到被拦截类的对象:
方法拦截对象就是上一篇中的asmAopMethodAdapter
具体修改为
所涉及类以打包。
代码运行环境 asm 3.3.1 jdk 1.6.
现在将要实现对参数传入值的拦截,不符合判断规则的传入值,将会被直接返回。
实现如下效果:
// 打印出参数传入值
start value:error
// 发现值等于 error 时直接返回
error,program will exit.
//属性值并未被更改
default
// 打印出传入值
start value:change
end value:change
// 属性值被更改
change
被拦截的方法是helloWorld中的sayHello
public class helloWorld {
public String va="default";
public void sayHello(String param){
va=param;
}
}
测试代码
asmAopGenerator aag = new asmAopGenerator();
helloWorld hw = (helloWorld) aag.proxy(helloWorld.class, "sayHello", "it's begin", "it's end");
// 传入值是error时直接返回 va的值没改变
hw.sayHello("error");
// 打印出default
System.out.println(hw.va);
// va的值被改变
hw.sayHello("change");
// 打印出 va的值为 change
System.out.println(hw.va);
注入到被拦截类的对象:
public class asmAopInvoker {
public static int methodEnd(String evtID){
System.out.println("end value:"+evtID);
return 0;
}
public static int methodStart(String evtID){
System.out.println("start value:"+evtID);
if(evtID.equals("error")){
System.out.println("error,program will exit.");
return 1;
}
return 0;
}
}
方法拦截对象就是上一篇中的asmAopMethodAdapter
具体修改为
public class asmAopMethodAdapter extends MethodAdapter implements Opcodes{
private final static int EXCEPTION_STACK = 2 + 1;//max_stack至少需要能够容纳2个常量地址(监控方法使用)和1个exception地址
private Label try_catch_start,try_catch_end;
private String startInfo,endInfo;
public asmAopMethodAdapter(MethodVisitor mv,String start,String end) {
super(mv);
try_catch_start = new Label();
try_catch_end = new Label();
startInfo = start;
endInfo = end;
}
public void visitCode() {
mv.visitCode();
mv.visitLabel(try_catch_start);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
// 加入if标签
Label if_Lable = new Label();
// 获得函数 methodStart 的返回值
mv.visitVarInsn(ALOAD, 1);
// 调用 methodStart函数
// (Ljava/lang/String;)I 意为:接受一个类型为string参数
// 返回值为int的函数
mv.visitMethodInsn(INVOKESTATIC, "asmAop/asmAopInvoker",
"methodStart", "(Ljava/lang/String;)I");
// 访问if 标签
// 疑惑 asm4-guide 中说明 IFEQ的意思是:jump if i == 0。但我在asm 3.3.1中貌似IFEQ是 jump if i==1
mv.visitJumpInsn(IFEQ, if_Lable);
// 写入 return
mv.visitInsn(RETURN);
// 结束if标签
mv.visitLabel(if_Lable);
}
public void visitInsn(int opcode){
if(opcode >= IRETURN && opcode <= RETURN){
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESTATIC, "asmAop/asmAopInvoker",
"methodEnd", "(Ljava/lang/String;)I");
}
mv.visitInsn(opcode);
}
public void visitEnd() {
mv.visitLabel(try_catch_end);
mv.visitTryCatchBlock(try_catch_start, try_catch_end, try_catch_end, null);
mv.visitInsn(Opcodes.ATHROW);
mv.visitEnd();
}
public void visitMaxs(int maxStack,int maxLocals){
//保证max stack足够大
mv.visitMaxs(Math.max(EXCEPTION_STACK,maxStack), maxLocals);
}
}
所涉及类以打包。
代码运行环境 asm 3.3.1 jdk 1.6.