`
victorzhzh
  • 浏览: 202088 次
  • 来自: ...
社区版块
存档分类
最新评论

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中如何操作类。

 

分享到:
评论
1 楼 wzx_it 2015-11-20  
   你就是牛人,联系方式留一个啊

相关推荐

    asm-analysis-5.0.3.jar

    asm-analysis-5.0.3.jar;asm-analysis-5.0.3.jar;asm-analysis-5.0.3.jar

    asm3.1.jar

    我学习spring程序,测试程序时.老出bug, 后来从网上找原因说asm.jar版本太低 现把好不容易找来的jar包共享给大家

    asm-5.0.4-API文档-中文版.zip

    赠送jar包:asm-5.0.4.jar; 赠送原API文档:asm-5.0.4-javadoc.jar; 赠送源代码:asm-5.0.4-sources.jar; 赠送Maven依赖信息文件:asm-5.0.4.pom; 包含翻译后的API文档:asm-5.0.4-javadoc-API文档-中文(简体)版...

    yuandaima.rar_asm 程序_site:www.pudn.com_随机数

    这是几个asm小程序。包括判断某一年是否为润年的程序;产生随机数并运算的程序;计算平台长度程序等

    asm-9.1-API文档-中文版.zip

    赠送jar包:asm-9.1.jar; 赠送原API文档:asm-9.1-javadoc.jar; 赠送源代码:asm-9.1-sources.jar; 赠送Maven依赖信息文件:asm-9.1.pom; 包含翻译后的API文档:asm-9.1-javadoc-API文档-中文(简体)版.zip; ...

    也是一个流水灯asm

    我是在keil 用的是汇编语言写的,希望大家看看

    asm-util.jar.zip

    标签:asm-util.jar.zip,asm,util,jar.zip包下载,依赖包

    keil arm编译链 v5 版本 error: unknown register name vfpcc in asm的解决方法

    keil arm编译链 v5 版本 error: unknown register name vfpcc in asm 务必安装在keil /arm 的目录下。

    ASM7使用指南.pdf

    ASM7使用指南;

    QT-ASM-转换器:GUI ASM到HEX以及HEX到ASM转换工具

    QT-ASM-转换器:GUI ASM到HEX以及HEX到ASM转换工具

    asm-7.1-API文档-中英对照版.zip

    赠送jar包:asm-7.1.jar; 赠送原API文档:asm-7.1-javadoc.jar; 赠送源代码:asm-7.1-sources.jar; 赠送Maven依赖信息文件:asm-7.1.pom; 包含翻译后的API文档:asm-7.1-javadoc-API文档-中文(简体)-英语-对照版...

    asm.jar各个版本

    asm-1.3.3.jar, asm-1.3.4.jar, asm-1.3.5.jar, asm-1.4.1.jar, asm-1.4.2.jar, asm-1.4.3.jar, asm-1.4.jar, asm-1.5.1.jar, asm-1.5.2.jar, asm-1.5.3.jar, asm-2.0.jar, asm-2.1.jar, asm-2.2.1-sources.jar, asm...

    asm-4.2-API文档-中文版.zip

    赠送jar包:asm-4.2.jar; 赠送原API文档:asm-4.2-javadoc.jar; 赠送源代码:asm-4.2-sources.jar; 赠送Maven依赖信息文件:asm-4.2.pom; 包含翻译后的API文档:asm-4.2-javadoc-API文档-中文(简体)版.zip; ...

    重建ASM磁盘组的步骤

    重建ASM磁盘组的,1: 保证使用ASM的数据库事先已经用RMAN做了备份 2: 关闭ASM实例 3: 使用dd命令清除ASM磁盘上的元数据 4: 重建ASM磁盘组 5: 恢复数据库

    安装oracle ASM所需的系统包:oracleasmlib、oracleasm-support

    oracleasmlib-2.0.12-1.el7.x86_64.rpm oracleasm-support-2.1.11-2.el7.x86_64.rpm 安装ASM所需的包:适用于CentOS7

    各种oracleasm rpm包(Linux下配置ASM使用)

    包含如下oracleasm包: kmod-oracleasm-2.0.6.rh1-3.el6.x86_64.rpm oracleasm-2.0.8-4.el6_6.src.rpm oracleasm-2.0.8-6.el6_7.src.rpm oracleasm-2.0.8-8.el7.src.rpm oracleasm-2.0.8-15.el7.centos.src.rpm ...

    asm-5.0.4-API文档-中英对照版.zip

    赠送jar包:asm-5.0.4.jar; 赠送原API文档:asm-5.0.4-javadoc.jar; 赠送源代码:asm-5.0.4-sources.jar; 赠送Maven依赖信息文件:asm-5.0.4.pom; 包含翻译后的API文档:asm-5.0.4-javadoc-API文档-中文(简体)-...

    asm-7.1-API文档-中文版.zip

    赠送jar包:asm-7.1.jar; 赠送原API文档:asm-7.1-javadoc.jar; 赠送源代码:asm-7.1-sources.jar; 赠送Maven依赖信息文件:asm-7.1.pom; 包含翻译后的API文档:asm-7.1-javadoc-API文档-中文(简体)版.zip; ...

    asm-6.2.1-API文档-中英对照版.zip

    赠送jar包:asm-6.2.1.jar; 赠送原API文档:asm-6.2.1-javadoc.jar; 赠送源代码:asm-6.2.1-sources.jar; 赠送Maven依赖信息文件:asm-6.2.1.pom; 包含翻译后的API文档:asm-6.2.1-javadoc-API文档-中文(简体)-...

    asm-9.1-API文档-中英对照版.zip

    赠送jar包:asm-9.1.jar; 赠送原API文档:asm-9.1-javadoc.jar; 赠送源代码:asm-9.1-sources.jar; 赠送Maven依赖信息文件:asm-9.1.pom; 包含翻译后的API文档:asm-9.1-javadoc-API文档-中文(简体)-英语-对照版...

Global site tag (gtag.js) - Google Analytics