java中如何使用asm动态的生成或修改一个class文件以及asm的架构思想

在开发中一般情况下我们写好的代码然后编译成class文件并运行属于静态的class文件生成,那是不是class文件就只有静态生成一种啊,其实不然,在jdk的动态代理应用Proxy类就是已经使用了动态生成一个class文件来实现代理功能的,只是这一部分我们都看不到,而asm是一个专门的字节码动态生成的一个框架,其架构使用的是生产、消费和过滤模式对应的接口和类分别是ClassReader读取一个Class文件属于生产模式,classWriter是生产一个class文件属于消费模式,ClassAdapter是对ClassWriter的过滤,做修改功能的,classReader接受一个ClassWriter并在方法中调用ClassWriter的所有的方法来实现生产并消费。当我们修改一个类的时候就必须继承ClassAdapter利用ClassAdapter中包含的ClassWriter对象对class文件进行修改。如果只是动态生成一个class就直接使用classWriter和CodeWriter就可以了。运用asm进行动态生成和修改一个class文静必须了解class文件的结构和一些指令。但是CGLib(Code Generator Library代码生成库)帮我们做了封装和扩展让我们更容易去实现这个功能,不用了解class文件的结构也可以做到。其中CGLib的类的动态代理就是利用asm字节码动态生成而实现的,在这里说一下CGLib只是对asm的封装和扩展,CGLib的对class文件及一个类的操作是基于asm的欢聚换说asm是CGLib的底层,关于asm可以参考asm使用手册。网上是可以下载的,有兴趣的话可以研究一下。下面给出一些实际操作的小例子:

public void generator()
 {//自动生成一个class文件
  ClassWriter cw=new ClassWriter(0);
  cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT, "com/test/bean/Base", null,"com/test/bean/Test", new String[]{"com/test/bean/IDAO"});
  cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC+Opcodes.ACC_FINAL, "name", "Ljava/lang/String;",null,"accp" ).visitEnd();
  cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC+Opcodes.ACC_FINAL, "age", "I",null, new Integer(20)).visitEnd();
  cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT,"hello", "()V", null,null).visitEnd();
  cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT,"add", "(Ljava/lang/Object;)V", null,null).visitEnd();
  cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT,"update","(Ljava/lang/Object;)V",null,null).visitEnd();
  cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT,"delete","(Ljava/lang/Object;)V", null,null).visitEnd();
  cw.visitEnd();
  byte[] b=cw.toByteArray();//构建好一个class文件
  ClassReader cr=new ClassReader(b);
  ClassWriter cw2=new ClassWriter(0);
  //给class文件添加一个方法
  cr.accept(new AddMethodAdapter(cw2,Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT,"get","(Ljava/lang/String;)Ljava/lang/Object;"), 0);
  //从class文件中移除一个方法
  //cr.accept(new RemoveMethodAdapter(cw2,"delete","(Ljava/lang/Object;)V"), false);
  b=cw2.toByteArray();//生成新的class文件
  try {
   FileOutputStream out=new FileOutputStream(new File("D:Base.class"));
   out.write(b);
   out.close();
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
/**
  * 移除方法过滤器
  * @author liurm
  *
  */
 public class RemoveMethodAdapter extends ClassAdapter {
        private String name;//方法名称
        private String desc;//方法描述
  public RemoveMethodAdapter(ClassVisitor classvisitor,String name,String desc) {
   super(classvisitor);
   // TODO Auto-generated constructor stub
   this.name=name;
   this.desc=desc;
  }
 
  public MethodVisitor visitMethod(int access, String name, String desc,
    String signature, String[] exceptions) {
   // TODO Auto-generated method stub
   if(name.equals(this.name)&&desc.equals(this.desc))
   {
    return null;//移除方法
   }
   return super.visitMethod(access, name, desc, signature, exceptions);
  }
 
 }
 /*
  * 添加方法过滤器
  * */
 public class AddMethodAdapter extends ClassAdapter{
  private int acc;//访问修饰符
        private String name;//方法名称
        private String desc;//方法描述
        private boolean isMethodPersent;//是否已经添加
  public AddMethodAdapter(ClassVisitor classvisitor,int acc,String name,String desc) {
   super(classvisitor);
   // TODO Auto-generated constructor stub
   this.acc=acc;
   this.name=name;
   this.desc=desc;
  }
 
  public MethodVisitor visitMethod(int access, String name, String desc,
    String signature, String[] exceptions) {
   // TODO Auto-generated method stub
   if(name.equals(this.name)&&desc.equals(this.desc))
   {//方法已经添加
    isMethodPersent=true;
   }
   return super.visitMethod(access, name, desc, signature, exceptions);
  }

  public void visitEnd() {
   // TODO Auto-generated method stub
   if(!isMethodPersent)
   {//未添加是才添加
    super.cv.visitMethod(acc, name, desc, null, null);
   }
   super.visitEnd();
  }
 
 }
 
 class PrintClass implements org.objectweb.asm.ClassVisitor{

  public void visitAttribute(Attribute attribute) {
   // TODO Auto-generated method stub
  
  }

  public void visitEnd() {
   // TODO Auto-generated method stub
   System.out.println("}");
  }

  public void visitInnerClass(String name, String outername, String innername, int access) {
   // TODO Auto-generated method stub
  
  }

  public void visit(int version, int access, String name, String signutre,
    String supername, String[] interfacename) {
   // TODO Auto-generated method stub
   System.out.println(name+" extends "+supername+"{");
  }

  public AnnotationVisitor visitAnnotation(String desc, boolean  visible) {
   // TODO Auto-generated method stub
   return null;
  }

  public FieldVisitor visitField(int access, String name, String desc,
    String signature, Object value) {
   // TODO Auto-generated method stub
   System.out.println(desc+" "+name);
   return null;
  }

  public MethodVisitor visitMethod(int access, String name, String desc,
    String signature, String[] exceptions) {
   // TODO Auto-generated method stub
   System.out.println(name+desc);
   return null;
  }

  public void visitOuterClass(String owner, String name, String desc) {
   // TODO Auto-generated method stub
  
  }

  public void visitSource(String arg0, String arg1) {
   // TODO Auto-generated method stub
  
  }
 
 }

生成Get,Set方法,一个普通的java类

ClassWriter cw=new ClassWriter(0);//手动计算内存
  cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC,"com/test/bean/Student",null,"java/lang/Object",null);//声明一个类
  cw.visitField(Opcodes.ACC_PRIVATE, "age", "I", null,new Integer(20)).visitEnd();//定义age字段
  cw.visitField(Opcodes.ACC_PRIVATE, "name", "Ljava/lang/String;",null,"accp").visitEnd();//定义name字段
  //构造函数
  MethodVisitor mv4=cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
  mv4.visitCode();
  mv4.visitVarInsn(Opcodes.ALOAD, 0);
  mv4.visitMethodInsn(Opcodes.INVOKESPECIAL, "com/test/bean/Student", "<init>", "()V");
  mv4.visitInsn(Opcodes.RETURN);
  mv4.visitMaxs(1, 1);
  mv4.visitEnd();
  //构建getAge方法
  MethodVisitor mv=cw.visitMethod(Opcodes.ACC_PUBLIC, "getAge", "()I", null,null);
  mv.visitCode();
  mv.visitVarInsn(Opcodes.ALOAD, 0);
  mv.visitFieldInsn(Opcodes.GETFIELD, "com/test/bean/Student", "age", "I");
  mv.visitInsn(Opcodes.IRETURN);
  mv.visitMaxs(1, 1);
  mv.visitEnd();
  //构建setAge方法
  MethodVisitor mv1=cw.visitMethod(Opcodes.ACC_PUBLIC, "setAge", "(I)V", null, null);
  mv1.visitCode();
  mv1.visitVarInsn(Opcodes.ALOAD, 0);
  mv1.visitVarInsn(Opcodes.ALOAD, 1);
  mv1.visitFieldInsn(Opcodes.PUTFIELD, "com/test/bean/Student", "age", "I");
  mv1.visitInsn(Opcodes.RETURN);
  mv1.visitMaxs(2, 2);
  mv1.visitEnd();
  //构建getName方法
  MethodVisitor mv2=cw.visitMethod(Opcodes.ACC_PUBLIC, "getName", "()Ljava/lang/String;", null,null);
  mv2.visitCode();
  mv2.visitVarInsn(Opcodes.ALOAD, 0);
  mv2.visitFieldInsn(Opcodes.GETFIELD, "com/test/bean/Student", "name", "Ljava/lang/String;");
  mv2.visitInsn(Opcodes.ARETURN);
  mv2.visitMaxs(1, 1);
  mv2.visitEnd();
  //构建setName方法
  MethodVisitor mv3=cw.visitMethod(Opcodes.ACC_PUBLIC, "setName", "(Ljava/lang/String;)V", null, null);
  mv3.visitCode();
  mv3.visitVarInsn(Opcodes.ALOAD, 0);
  mv3.visitVarInsn(Opcodes.ALOAD, 1);
  mv3.visitFieldInsn(Opcodes.PUTFIELD, "com/test/bean/Student", "name", "Ljava/lang/String;");
  mv3.visitInsn(Opcodes.RETURN);
  mv3.visitMaxs(2, 2);
  mv3.visitEnd();
  //sayhello方法
  MethodVisitor mv5=cw.visitMethod(Opcodes.ACC_PUBLIC, "sayhello", "(Ljava/lang/String;)Ljava/lang/String;", null, null);
  mv5.visitCode();
  mv5.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder");
  mv5.visitInsn(Opcodes.DUP);
  mv5.visitLdcInsn("Hello:");
  mv5.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
  mv5.visitVarInsn(Opcodes.ALOAD, 1);
  mv5.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
  mv5.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
  mv5.visitInsn(Opcodes.ARETURN);
  mv5.visitMaxs(3, 2);
  mv5.visitEnd();
  //静态块
  MethodVisitor mv6=cw.visitMethod(Opcodes.ACC_STATIC, "<clinit>","()V", null,null);
  mv6.visitCode();
  //System.out.println("Hello World!");
  mv6.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
  mv6.visitLdcInsn("Hello World!");
  mv6.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
  //创建数组int [] a=new int[5];
  //mv6.visitInsn(Opcodes.ICONST_5);
  //int [] a=new int[6];
  mv6.visitLdcInsn(new Integer(6));
  //mv6.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_INT);
  mv6.visitVarInsn(Opcodes.NEWARRAY, Opcodes.T_INT);
  mv6.visitVarInsn(Opcodes.ASTORE, 4);
  mv6.visitInsn(Opcodes.RETURN);
  mv6.visitMaxs(4,0);
  mv6.visitEnd();
  cw.visitEnd();
  byte[] b=cw.toByteArray();//可以装载到JVM中了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值