概述
一、什么是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中如何操作类。
最后
以上就是友好外套为你收集整理的ASM系列之一:初探ASM的全部内容,希望文章能够帮你解决ASM系列之一:初探ASM所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复