`
xkorey
  • 浏览: 151097 次
  • 性别: Icon_minigender_1
  • 来自: 石家庄
社区版块
存档分类
最新评论

ASM函数监听实现(三)拦截注入函数的参数值 (函数执行前)

    博客分类:
  • ASM
阅读更多
上一篇ASM中打印出了被注入函数参数的传入值,http://xkorey.iteye.com/admin/blogs/1667944

现在将要实现对参数传入值的拦截,不符合判断规则的传入值,将会被直接返回。
实现如下效果:
// 打印出参数传入值
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.
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics