首页 > 代码库 > asm示例
asm示例
前些天看aop就看到了cglib,看cglib又看到了asm,模仿着做了个示例。利用asm修改字节码,能实现编译不通过执行通的过的效果,挺有意思。
一个简单的待修改类:
package com.asm.zjc; public class C { public void m() throws InterruptedException{ Thread.sleep(300); } }对其进行修改的类:
package com.asm.zjc; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassAdapter; public class Generator { public static void main(String[] arg){ try{ ClassReader cr = new ClassReader("com/asm/zjc/C"); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassAdapter classAdapter = new AddTimeClassAdapter(cw); //使给定的访问者访问Java类的ClassReader cr.accept(classAdapter, ClassReader.SKIP_DEBUG); byte[] data = http://www.mamicode.com/cw.toByteArray();>
其中用到了类适配器:package com.asm.zjc; import org.objectweb.asm.*; public class AddTimeClassAdapter extends ClassAdapter { private String owner; private boolean isInterface; public AddTimeClassAdapter(ClassVisitor cv) { super(cv); } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces){ cv.visit(version, access, name, signature, superName, interfaces); owner = name; isInterface = (access & Opcodes.ACC_INTERFACE) != 0; } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions){ MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); if(!name.equals("<init>") && !isInterface && mv!=null){ mv=new AddTimeMethodAdapter(mv); } return mv; } @Override public void visitEnd(){ if(!isInterface){ FieldVisitor fv = cv.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC, "timer", "J", null, null); if(fv!=null){ fv.visitEnd(); } } cv.visitEnd(); } class AddTimeMethodAdapter extends MethodAdapter{ public AddTimeMethodAdapter(MethodVisitor mv){ super(mv); } @Override public void visitCode(){ mv.visitCode(); mv.visitFieldInsn(Opcodes.GETSTATIC, owner, "timer", "J"); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J"); mv.visitInsn(Opcodes.LSUB); mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, "timer", "J"); } @Override public void visitInsn(int opcode){ if((opcode>=Opcodes.IRETURN && opcode<=Opcodes.RETURN) || opcode==Opcodes.ATHROW){ mv.visitFieldInsn(Opcodes.GETSTATIC, owner, "timer", "J"); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J"); mv.visitInsn(Opcodes.LADD); mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, "timer", "J"); } mv.visitInsn(opcode); } @Override public void visitMaxs(int maxStack, int maxLocal){ mv.visitMaxs(maxStack+4, maxLocal); } } }
最后写一个测试程序验证:package com.asm.zjc; public class Test { @SuppressWarnings("static-access") public static void main(String[] args)throws InterruptedException{ C c1=new C(); c1.m(); System.out.println(C.timer); } }
注意第8行是不能通过编译的,但可以执行成功。
其实我们用下面的命令行反编译class文件,也可以了解字节码的结构:
D:\software\eclipse\workspace\study_asm\bin>javap -c -verbose com.asm.zjc.C >aaa.java
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。