曹工说Spring Boot源码(24)-- Spring注解扫描的瑞士军刀,asm技术实战(上) (2)

测试代码

import org.objectweb.asm.ClassReader; import java.io.IOException; import java.util.List; public class TestClassVisit { public static void main(String[] args) throws IOException { // 使用classreader读取目标类 ClassReader classReader = new ClassReader("com.yn.onlyvisit.Person"); // new一个visitor MyClassVistor classVisitor = new MyClassVistor(); // 传入classreader classReader.accept(classVisitor,ClassReader.SKIP_DEBUG); // 此时,目标类已经读取完毕,我们可以打印看看效果 List<String> methodList = classVisitor.getMethodList(); System.out.println(methodList); System.out.println(classVisitor.getAnnotationOnClass()); } }

输出如下:

field:name
field:age
visitMethod:
visitMethod: getName
visitMethod: setName
visitMethod: getAge
visitMethod: setAge
[, getName, setName, getAge, setAge]
[Lcom/yn/onlyvisit/CustomAnnotationOnClass;]

ASM的核心之生成全新class 案例讲解

注意,我们限定的是,生成全新的class,为什么限定这么死,因为还有一种是,在已经存在的类的基础上,修改class。

生成全新class的场景也是常见的,比如cglib底层就使用了asm,代理类是动态生成的,对吧?虽然我还没验证,但基本就是目前要讲的这种场景。

还有就是,fastjson里也用了asm,至于里面是否是生成全新class,留带验证。

asm的官方文档,有下面这样一个例子。

目标类如下,我们的目标,就是生成这样一个类的class:

package pkg; public interface Comparable extends Mesurable { int LESS = -1; int EQUAL = 0; int GREATER = 1; int compareTo(Object o); }

我们只需要如下几行代码,即可完成该目标。

package com.yn.classgenerate; import org.objectweb.asm.ClassWriter; import java.io.*; import java.lang.reflect.Field; import static org.objectweb.asm.Opcodes.*; public class TestClassWriter { public static void main(String[] args) throws IOException { ClassWriter cw = new ClassWriter(0); cw.visit(V1_7, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, "pkg/Comparable", null, "java/lang/Object", null); 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(); cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo", "(Ljava/lang/Object;)I", null, null).visitEnd(); cw.visitEnd(); byte[] b = cw.toByteArray(); File file = new File("F:\\gitee-ckl\\all-simple-demo-in-work\\asm-demo\\src\\main\\java\\com\\yn\\classgenerate\\Target.class"); FileOutputStream fos = new FileOutputStream(file); fos.write(b); fos.close(); } }

执行上述代码,在指定位置,就会生成一个Target.class,反编译之后,如下:

曹工说Spring Boot源码(24)-- Spring注解扫描的瑞士军刀,asm技术实战(上)

ClassWriter初识

上面那个demo,是否够神奇?为什么这么神奇呢,核心都在ClassWriter这个类。

这个类,大家可以理解为,一个class文件包含了很多东西,对吧?常量池、field集合、method集合、注解、class名、实现的接口集合等等,这个classWriter呢,其中就有很多field,分别来存储这些东西。

曹工说Spring Boot源码(24)-- Spring注解扫描的瑞士军刀,asm技术实战(上)

注意的是,上图中,有些字段,比如firstField,为什么不是集合呢?按理说,一个class里很多field啊,因为,这里用了链表结构来存储field。我们看这个field上的注释。

/** * The fields of this class, stored in a linked list of {@link FieldWriter} linked via their * {@link FieldWriter#fv} field. This field stores the first element of this list. */ private FieldWriter firstField;

看到了吧,链表结构。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfxsf.html