浏览 2498 次
锁定老帖子 主题:ASM函数监听实现
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-06-05
最后修改:2012-06-11
2.资料:在网上看到关于asm的技术资料,写了一个简单的实现。参考链接如下: http://www.cnblogs.com/eafy/archive/2008/06/18/1224633.html http://alvinqq.iteye.com/blog/940965 http://www.ibm.com/developerworks/cn/java/j-lo-asm30/ http://ayufox.iteye.com/blog/668917 3.代码:asmAopClassAdapter 该类对目标类进行操作。 public class asmAopClassAdapter extends ClassAdapter{ private String enhancedSuperName,enhancedName; private String method; private String startInfo,endInfo; public asmAopClassAdapter(ClassVisitor cv,String methodName,String start,String end) { //Responsechain 的下一个 ClassVisitor,这里我们将传入 ClassWriter, // 负责改写后代码的输出 super(cv); method = methodName; startInfo = start; endInfo = end; } // 重写 visitMethod,访问到 "method" 方法时, // 给出自定义 MethodVisitor,实际改写方法内容 public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); MethodVisitor wrappedMv = mv; if (mv != null) { if (name.equals(method)) { wrappedMv = new asmAopMethodAdapter(mv,startInfo,endInfo); } else if (name.equals("<init>")) { wrappedMv = new ChangeToChildConstructorMethodAdapter(mv, enhancedSuperName); } } return wrappedMv; } public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { enhancedName = name.replace("/", "$")+"$EnhancedByASM"; // 改变类命名 enhancedSuperName = name; // 改变父类 super.visit(version, access, enhancedName, signature, enhancedSuperName, interfaces); } public String getEnhancedName() { return enhancedName; } } 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.visitLdcInsn(startInfo); //asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker", "methodStart", "(Ljava/lang/String;)V"); } public void visitInsn(int opcode){ if(opcode >= IRETURN && opcode <= RETURN){ mv.visitLdcInsn(endInfo); //asmAopInvoker 这里写类的路径例如:com.asm.asmAopInvoker 应写成 com/asm/asmAopInvoker mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker", "methodEnd", "(Ljava/lang/String;)V"); } mv.visitInsn(opcode); } public void visitEnd() { mv.visitLabel(try_catch_end); mv.visitTryCatchBlock(try_catch_start, try_catch_end, try_catch_end, null); mv.visitLdcInsn(endInfo); mv.visitMethodInsn(INVOKESTATIC, "asmAopInvoker", "methodEnd", "(Ljava/lang/String;)V"); mv.visitInsn(Opcodes.ATHROW); mv.visitEnd(); } //public void visitMaxs(int maxStack,int maxLocals){ //保证max stack足够大 // mv.visitMaxs(Math.max(EXCEPTION_STACK,maxStack), maxLocals); //} } ChangeToChildConstructorMethodAdapter该类生成目标类的子类。 public class ChangeToChildConstructorMethodAdapter extends MethodAdapter { private String superClassName; public ChangeToChildConstructorMethodAdapter(MethodVisitor mv, String superClassName) { super(mv); this.superClassName = superClassName; } public void visitMethodInsn(int opcode, String owner, String name, String desc) { // 调用父类的构造函数时 if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) { owner = superClassName; } super.visitMethodInsn(opcode, owner, name, desc);// 改写父类为 superClassName } } asmAopGenerator 一个工具类,生成代理目标类的对象。 public class asmAopGenerator { private AOPGeneratorClassLoader classLoader ; public asmAopGenerator(){ classLoader = new AOPGeneratorClassLoader(); } public Object proxy(Class c,String methodName,String startInfo,String endInfo) { try{ if( c != null){ String classPach = c.toString().replace("/", "."); ClassReader cr = new ClassReader(classPach.substring(6,classPach.length())); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); asmAopClassAdapter classAdapter = new asmAopClassAdapter(cw,methodName,startInfo,endInfo); cr.accept(classAdapter, ClassReader.SKIP_DEBUG); byte[] data = cw.toByteArray(); Class obj = classLoader.defineClassFromClassFile(classAdapter.getEnhancedName(), data); //TODO:隐藏BUG return obj.newInstance(); }}catch(Exception e){ e.printStackTrace(); } return null; } class AOPGeneratorClassLoader extends ClassLoader { public Class defineClassFromClassFile(String className, byte[] classFile) throws ClassFormatError { return defineClass(className, classFile, 0, classFile.length); } } } asmAopInvoker 函数注入类 public class asmAopInvoker { public static void methodEnd(String evtID){ System.out.println(evtID); } public static void methodStart(String evtID){ System.out.println(evtID); } } 测试类 public class helloWorld { public void sayHello(){ System.out.println("helloWorld...."); } public static void main(String[]args){ asmAopGenerator aag = new asmAopGenerator(); helloWorld hw = (helloWorld) aag.proxy(helloWorld.class, "sayHello", "it's begin", "it's end"); hw.sayHello(); } } 输出结果 it's begin helloWorld.... it's end 4.目的基本达成。 5.待改进,在监听函数执行后,是用的try和catch抛异常的方式来实现。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-06-08
类名首字母大写啊。
另外既然用来ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS) 那么 //保证max stack足够大 mv.visitMaxs(Math.max(EXCEPTION_STACK,maxStack), maxLocals); 这里的maxstack 和 maxlocals 的值就不起作用了。 asm会自动计算的。 |
|
返回顶楼 | |
发表时间:2012-06-11
wensiqun 写道 类名首字母大写啊。 另外既然用来ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS) 那么 //保证max stack足够大 mv.visitMaxs(Math.max(EXCEPTION_STACK,maxStack), maxLocals); 这里的maxstack 和 maxlocals 的值就不起作用了。 asm会自动计算的。 已将visitMaxs,方法屏蔽。多谢指正。 |
|
返回顶楼 | |