曹工说Spring Boot源码(23)-- ASM又立功了,Spring原来是这么递归获取注解的元注解的 (4)

新建一个AnnotationMetadataReadingVisitor类的实例,这个继承了ClassVisitor抽象类,这个visitor里面定义了一堆的回调方法:

public abstract class ClassVisitor { public ClassVisitor(int api); public ClassVisitor(int api, ClassVisitor cv); public void visit(int version, int access, String name, String signature, String superName, String[] interfaces); public void visitSource(String source, String debug); public void visitOuterClass(String owner, String name, String desc); // 解析到class文件中的注解时回调本方法 AnnotationVisitor visitAnnotation(String desc, boolean visible); public void visitAttribute(Attribute attr); public void visitInnerClass(String name, String outerName,String innerName,int access); // 解析到field时回调 public FieldVisitor visitField(int access, String name, String desc,String signature, Object value); // 解析到method时回调 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions); void visitEnd(); }

这其中,方法的访问顺序如下:

visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )* ( visitInnerClass | visitField | visitMethod )* visitEnd 代表: visit必须最先访问; 接着是最多一次的visitSource,再接着是最多一次的visitOuterClass; 接着是任意多次的visitAnnotation | visitAttribute ,这两个,顺序随意; 再接着是,任意多次的visitInnerClass | visitField | visitMethod ,顺序随意 最后,visitEnd

这个顺序的? * () 等符号,其实类似于正则表达式的语法,对吧,还是比较好理解的。

然后呢,我对visitor的理解,现在感觉类似于spring里面的event listener机制,比如,spring的生命周期中,发布的事件,有如下几个,其实也是有顺序的:

曹工说Spring Boot源码(23)-- ASM又立功了,Spring原来是这么递归获取注解的元注解的

这里还有官网提供的一个例子:

public class ClassPrinter extends ClassVisitor { public ClassPrinter() { super(ASM4); } 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("}"); } }

将第二步的visitor策略,传递给classReader,classReader开始进行解析

getAnnotationTypes的回调处理

曹工说Spring Boot源码(23)-- ASM又立功了,Spring原来是这么递归获取注解的元注解的

曹工说Spring Boot源码(23)-- ASM又立功了,Spring原来是这么递归获取注解的元注解的

我们接着回到getAnnotationTypes的实现,大家看了上面2个图,应该大致知道visitAnnotation的实现了:

@Override public AnnotationVisitor visitAnnotation(final String desc, boolean visible) { String className = Type.getType(desc).getClassName(); this.annotationSet.add(className); return new AnnotationAttributesReadingVisitor(className, this.attributeMap, this.metaAnnotationMap, this.classLoader, this.logger); }

这里每访问到一个注解,就会加入到field: annotationSet中。

注解上的元注解,如何读取

大家再看看上面的代码,我们返回了一个AnnotationAttributesReadingVisitor,这个visitor会在:asm访问注解的具体属性时,其中的如下方法被回调。

@Override public void doVisitEnd(Class<?> annotationClass) { super.doVisitEnd(annotationClass); List<AnnotationAttributes> attributes = this.attributesMap.get(this.annotationType); if(attributes == null) { this.attributesMap.add(this.annotationType, this.attributes); } else { attributes.add(0, this.attributes); } Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>(); // 1 for (Annotation metaAnnotation : annotationClass.getAnnotations()) { // 2 recusivelyCollectMetaAnnotations(metaAnnotationTypeNames, metaAnnotation); } if (this.metaAnnotationMap != null) { this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames); } } // 3 private void recusivelyCollectMetaAnnotations(Set<String> visited, Annotation annotation) { if(visited.add(annotation.annotationType().getName())) { this.attributesMap.add(annotation.annotationType().getName(), AnnotationUtils.getAnnotationAttributes(annotation, true, true)); // 获取本注解上的元注解 for (Annotation metaMetaAnnotation : annotation.annotationType().getAnnotations()) { // 4 递归调用自己 recusivelyCollectMetaAnnotations(visited, metaMetaAnnotation); } } }

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

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