0.代码结构
1.目标类
/**
* @Description 目标对象测试类
* @Date 2021-02-23 15:23
*/
public class Test {
int i = 0;
public int getI() {
return this.i;
}
}
2.自定义类加载器
/**
* @Description 自定义类加载器
* @Date 2021-02-23 14:46
*/
public class MyClassLoader extends ClassLoader {
public Class defineClass(String className, byte[] classBytes) {
return super.defineClass(className, classBytes, 0, classBytes.length);
}
}
3.类的打印
import org.objectweb.asm.*;
import java.io.IOException;
import static org.objectweb.asm.Opcodes.ASM4;
/**
* @Description asm 打印类 继承ClassVisitor
* @Date 2021-02-23 15:12
*/
public class MyClassPrint extends ClassVisitor {
public MyClassPrint() {
super(ASM4);
}
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
System.out.println(name + " extends " + superName + " {");
}
public void visitSource(String source, String debug) {
}
public void visitOuterClass(String owner, String name, String desc) {
}
public AnnotationVisitor visitAnnotation(String desc,
boolean visible) {
return null;
}
public void visitAttribute(Attribute attr) {
}
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
}
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
System.out.println(" " + desc + " " + name);
return null;
}
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
System.out.println(" " + name + desc);
return null;
}
public void visitEnd() {
System.out.println("}");
}
public static void main(String[] args) throws IOException {
MyClassPrint cp = new MyClassPrint();//cp中相对应的visit方法 写自己想要做的事情
//读取jdk自带的类
ClassReader cr = new ClassReader("java.lang.Runnable");//cr去读取目标类class
cr.accept(cp, 0);//read通过visit去读取.class内容,所以我们在visit中写想要进行的方法
//读取自己的类
ClassReader cr2 = new ClassReader(MyClassPrint.class.getClassLoader().getResourceAsStream("asm/Test.class"));
cr2.accept(cp, 0);
}
}
4.类的生成
import org.objectweb.asm.ClassWriter;
import static org.objectweb.asm.Opcodes.*;
/**
* @Description 生成类
* @Date 2021-02-23 15:26
* 类的实际样子:
* package asm;
* public interface Comparable {
* int LESS = -1;
* int EQUAL = 0;
* int GREATER = 1;
* int compareTo(Object o);
* }
*/
public class MyClassWriter {
public static void main(String[] args) {
ClassWriter cw = new ClassWriter(0);// ClassWriter继承ClassVisitor
//相当于在设置.class信息
//生成基础信息1.5版本, public abstract interface Comparable类,路径在asm包下, 父类Object
cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
"asm/Comparable", null, "java/lang/Object",
null);
//生成属性 名字less I表示int 默认值-1
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "LESS", "I",
null, new Integer(-1)).visitEnd();
//生成属性
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "EQUAL", "I",
null, new Integer(0)).visitEnd();
//生成属性
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "GREATER", "I",
null, new Integer(1)).visitEnd();
//生成方法 compareTo 参数Object 返回值I int
cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo",
"(Ljava/lang/Object;)I", null, null).visitEnd();
//结束设置
cw.visitEnd();
byte[] b = cw.toByteArray();
MyClassLoader cl = new MyClassLoader();
Class c = cl.defineClass("asm.Comparable", b); //加载生成的类 注意没有生成实际文件
System.out.println(c.getMethods()[0].getName());
}
}
5.代理方法对象
/**
* @Description
* @Date 2021-02-23 16:07
*/
public class TimeProxy {
//需要插入的代理方法
public static void before() {
System.out.println("tp before");
}
}
6.动态代理
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import java.io.File;
import java.io.FileOutputStream;
import static org.objectweb.asm.Opcodes.ASM4;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
/**
* @Description 动态代理底层
* @Date 2021-02-23 15:54
*/
public class MyClassTransFormer {
public static void main(String[] args) throws Exception {
ClassReader cr = new ClassReader(MyClassPrint.class.getClassLoader().getResourceAsStream("asm/Test.class"));
ClassWriter cw = new ClassWriter(0);
ClassVisitor cv = new ClassVisitor(ASM4, cw) {//把classwriter包一层 cv->cw
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
return new MethodVisitor(ASM4, mv) {
@Override
public void visitCode() {
// System.out.println(" "+name+" ");
if (name.equals("getI")) {//只在getI加before方法 构造器不加
//在原方法前,添加方法
visitMethodInsn(INVOKESTATIC, "asm/TimeProxy", "before", "()V", false);
}
//原方法
super.visitCode();
}
};
}
};
cr.accept(cv, 0);//cr->cv->cw cv起桥梁的作用,把cr和cw连通
byte[] b2 = cw.toByteArray();//获得修改后的类的二进制字节
//生成class文件
String path = (String) System.getProperties().get("user.dir");
// System.out.println(path);
File f = new File(path + "/asm/");
f.mkdirs();
FileOutputStream fos = new FileOutputStream(new File(path + "/asm/Test.class"));
fos.write(b2);
fos.flush();
fos.close();
}
}
个人理解:对于asm来说,我们写好的类编译后的class文件,就像一块块拼起来的积木,asm可以对这个积木进行重新拼装。
asm官网,可以查看官网中的asm4-guide.pdf。若打开太慢,链接: https://pan.baidu.com/s/1---_yuxqi8OQScDnb53ctw 提取码: p4qn
B站马士兵视频讲解 36分钟左右开始讲asm部分