ASM(一) 初识ASM

 

一、什么是ASM

      首先看下官方中的说明 ASM a very small and fast Java bytecode manipulation framework。

ASM是一个JAVA字节码分析、创建和修改的开源应用框架。它可以动态生成二进制格式的stub类或其他代理类,或者在类被JAVA虚拟机装入内存之前,动态修改类。在ASM中提供了诸多的API用于对类的内容进行字节码操作的方法。与传统的BCEL和SERL不同,在ASM中提供了更为优雅和灵活的操作字节码的方式。ASM相当小巧,并且它有更高的执行效率,是BCEL的7倍,SERP的11倍以上(摘自网络,具体没有测试)。目前ASM已被广泛的开源应用架构所使用,例如:Spring、Hibernate等。

二、ASM能做什么

      我们都知道,一般情况下,Class文件是通过javac编译器产生的,然后通过类加载器加载到虚拟机内,再通过执行引擎去执行。现在我们可以通过ASM的API直接生成符合Java虚拟机规范的Class字节流,这样,ASM做的事情一定程度上正是javac解释器做的工作。

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

     那么,我们就可以通过ASM来实现诸如代码生成,代码混淆,代码转换等等以字节码为操作目标的工作。

三、ASM大体结构

 

四、Java二进制(class)文件的格式

     要想驾驭ASM,先要了解一下JAVA的CLASS文件格式。JAVA的CLASS文件通常是树型结构。根节点包含以下元素:

  • ConstantPool:符号表;
  • FieldInfo:类中的成员变量信息;
  • MethodInfo:类中的方法描述;
  • Attribute:可选的附加节点。

      FieldInfo节点包含成员变量的名称,诸如public,private,static等的标志。

      ConstantValue属性用来存储静态的不变的成员变量的值。

      Deprecated和Synthetic被用来标记一个成员变量是不被推荐的或由编译器生成的。

      MethodInfo节点包含方法的名称,参数的类型和和它的返回值,方法是公有的,私有的或静态的等标志。

      MethodInfo包含可选的附加属性,其中最重要的是Code属性,它包含非抽象的方法的代码。

      Exceptions属性包含方法将抛出的Exception的名称。

      Deprecated和Synthetic属性的信息同上面的FieldInfo的定义一样。

 

      根节点的可选属性有SourceFile,InnerClasses和Deprecated。

      SourceFile用来存储被编译成字节码的源代码文件的原始名称;

      InnerClasses存储内部类的信息。由于这些属性的存在,java 的类格式是可以扩展的,也就是说可以在一个class中 附加一些非标准的属性, java虚拟机会忽略这些不可识别的属性,正常的加载这个class。

 

ConstantPool是一个由数字或字符串常量的索引组成的队列,或由此类的树的其他节点引用的,由其他对象创建的被引用常量的索引组成的队列。这个表的目标是为了减少冗余。例如,FieldInfo节点不包含节点的名称,只包含它在这一表中的索引。同样的,GETFIELD和PUTFIELD不直接包含成员变量的名称,只包含名称的索引。

 

五、体验ASM的威力

     相信我们还记得学习Java的第一个例子 HelloWorld.java,那么我们就用ASM生成我们的第一个字节文件 HelloWorld.class。

1、现将代码给出,然后逐步解释:

package com.wy.asm;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

/**
 * ASM
 * 
 * @author wy
 * 
 */
public class AsmGenerateCar {
	public void generateClass() {
		//
		ClassWriter clazzWriter = new ClassWriter(0);
		clazzWriter.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, "com/wy/asm/HelloWorld", null, "java/lang/Object", null);
		
		//
		String setMethodDesc = "(" + Type.getDescriptor(String[].class) + ")V";
		MethodVisitor mv = clazzWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", setMethodDesc, null, null);
		mv.visitCode();
		mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
		mv.visitLdcInsn("Hello World!");
		mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");  
		mv.visitInsn(Opcodes.RETURN);
		mv.visitMaxs(0, 0);
		mv.visitEnd();
		
		//
		byte[] classFile = clazzWriter.toByteArray();
		clazzWriter.visitEnd();
		
		//
		try {
			String path = Thread.currentThread().getContextClassLoader()
					.getResource("").getPath().replaceAll("%20", " ");
			FileOutputStream fos = new FileOutputStream(new File(path + "com/wy/asm/HelloWorld.class"));
			try {
				fos.write(classFile);
				fos.flush();
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}

		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		}

	}

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

}
 

执行上面的代码会在目录下生成我们想要的字节文件,来张图片验证:


2、使用反编译工具Java Decompiler 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值