ASM系列之一:初探ASM

一、什么是ASM

    ASM是一个JAVA字节码分析、创建和修改的开源应用框架。在ASM中提供了诸多的API用于对类的内容进行字节码操作的方法。与传统的BCEL和SERL不同,在ASM中提供了更为优雅和灵活的操作字节码的方式。目前ASM已被广泛的开源应用架构所使用,例如:Spring、Hibernate等。

二、ASM能干什么

    分析一个类、从字节码角度创建一个类、修改一个已经被编译过的类文件

三、ASM初探例子

    这里我们使用ASM的CoreAPI(ASM提供了两组API:Core和Tree,Core是基于访问者模式来操作类的,而Tree是基于树节点来操作类的)创建一个MyClass类,目标类如下:

public class MyClass {
	private String name;
	
	public Myclass(){
		this.name = "zhangzhuo";
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

 这个类在构造方法中初始化了属性name,并提供了两个public方法来修改和访问name属性。

 

 接下来就要书写创建这个类的代码了,现将代码给出,然后逐步解释,代码如下:

   代码1:

public class GenerateClass {
	public void generateClass() {

                //方法的栈长度和本地变量表长度用户自己计算
		ClassWriter classWriter = new ClassWriter(0);	
	
                //Opcodes.V1_6指定类的版本
                //Opcodes.ACC_PUBLIC表示这个类是public,
                //“org/victorzhzh/core/classes/MyClass”类的全限定名称
                //第一个null位置变量定义的是泛型签名,
                //“java/lang/Object”这个类的父类
                //第二个null位子的变量定义的是这个类实现的接口
classWriter.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC,
				"org/victorzhzh/core/classes/MyClass", null,
				"java/lang/Object", null);
               
		ClassAdapter classAdapter = new MyClassAdapter(classWriter);

		classAdapter.visitField(Opcodes.ACC_PRIVATE, "name",
				Type.getDescriptor(String.class), null, null);//定义name属性

		classAdapter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null,
				null).visitCode();//定义构造方法

		String setMethodDesc = "(" + Type.getDescriptor(String.class) + ")V";
		classAdapter.visitMethod(Opcodes.ACC_PUBLIC, "setName", setMethodDesc,
				null, null).visitCode();//定义setName方法

		String getMethodDesc = "()" + Type.getDescriptor(String.class);
		classAdapter.visitMethod(Opcodes.ACC_PUBLIC, "getName", getMethodDesc,
				null, null).visitCode();//定义getName方法

		byte[] classFile = classWriter.toByteArray();//生成字节码

		MyClassLoader classLoader = new MyClassLoader();//定义一个类加载器
		Class clazz = classLoader.defineClassFromClassFile(
				"org.victorzhzh.core.classes.MyClass", classFile);
		try {//利用反射方式,访问getName
			Object obj = clazz.newInstance();
			Method method = clazz.getMethod("getName");
                        System.out.println(obj.toString());
			System.out.println(method.invoke(obj, null));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	class MyClassLoader extends ClassLoader {
		public Class defineClassFromClassFile(String className, byte[] classFile)
				throws ClassFormatError {
			return defineClass(className, classFile, 0, classFile.length);
		}
	}

	public static void main(String[] args) {
		GenerateClass generateClass = new GenerateClass();
		generateClass.generateClass();
	}
}

   代码2:

public class MyClassAdapter extends ClassAdapter {

	public MyClassAdapter(ClassVisitor cv) {
		super(cv);
	}

	@Override
	public MethodVisitor visitMethod(int access, String name, String desc,
			String signature, String[] exceptions) {
		MethodVisitor methodVisitor = cv.visitMethod(access, name, desc,
				signature, exceptions);
		if (name.equals("<init>")) {
			return new InitMethodAdapter(methodVisitor);
		} else if (name.equals("setName")) {
			return new SetMethodAdapter(methodVisitor);
		} else if (name.equals("getName")) {
			return new GetMethodAdapter(methodVisitor);
		} else {
			return super.visitMethod(access, name, desc, signature, exceptions);
		}
	}

        //这个类生成具体的构造方法字节码
	class InitMethodAdapter extends MethodAdapter {
		public InitMethodAdapter(MethodVisitor mv) {
			super(mv);
		}

		@Override
		public void visitCode() {
			mv.visitVarInsn(Opcodes.ALOAD, 0);
			mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object",
					"<init>", "()V");//调用父类的构造方法
			mv.visitVarInsn(Opcodes.ALOAD, 0);
			mv.visitLdcInsn("zhangzhuo");//将常量池中的字符串常量加载刀栈顶
			mv.visitFieldInsn(Opcodes.PUTFIELD,
					"org/victorzhzh/core/classes/MyClass", "name",
					Type.getDescriptor(String.class));//对name属性赋值
			mv.visitInsn(Opcodes.RETURN);//设置返回值
			mv.visitMaxs(2, 1);//设置方法的栈和本地变量表的大小
		}
	};

        //这个类生成具体的setName方法字节码	
        class SetMethodAdapter extends MethodAdapter {
		public SetMethodAdapter(MethodVisitor mv) {
			super(mv);
		}

		@Override
		public void visitCode() {
			mv.visitVarInsn(Opcodes.ALOAD, 0);
			mv.visitVarInsn(Opcodes.ALOAD, 1);
			mv.visitFieldInsn(Opcodes.PUTFIELD,
					"org/victorzhzh/core/classes/MyClass", "name",
					Type.getDescriptor(String.class));
			mv.visitInsn(Opcodes.RETURN);
			mv.visitMaxs(2, 2);
		}

	}

       
         //这个类生成具体的getName方法字节
        class GetMethodAdapter extends MethodAdapter {

		public GetMethodAdapter(MethodVisitor mv) {
			super(mv);
		}

		@Override
		public void visitCode() {
			mv.visitVarInsn(Opcodes.ALOAD, 0);
			mv.visitFieldInsn(Opcodes.GETFIELD,
					"org/victorzhzh/core/classes/MyClass", "name",
					Type.getDescriptor(String.class));//获取name属性的值
			mv.visitInsn(Opcodes.ARETURN);//返回一个引用,这里是String的引用即name
			mv.visitMaxs(1, 1);
		}
	}
}

   运行结果:

org.victorzhzh.core.classes.MyClass@1270b73
zhangzhuo

   这个例子只是简单地介绍了一下ASM如何创建一个类,接下来的几个章节,将详细介绍ASM的CoreAPI和TreeAPI中如何操作类。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值