asm

本文是ASM系列教程,详细介绍了ASM的基本概念、功能、使用示例,包括创建类、分析类、修改类属性和方法。ASM是一个强大的Java字节码框架,广泛应用于Spring、Hibernate等项目。通过ASM,可以实现动态代理、代码增强等功能。
摘要由CSDN通过智能技术生成

https://blog.csdn.net/coslay/article/details/43370985

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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值