如何实现一个简易版的 Spring - 如何实现 @Component 注解 (3)

第二个类 AnnotationMetadataReadingVisitor 用来获取注解的类型,然后通过构造方法传给 AnnotataionAttributesVisitor,为获取注解属性做准备,代码实现如下:

/** * @author mghio * @since 2021-02-14 */ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata { private final Set<String> annotationSet = new LinkedHashSet<>(8); private final Map<String, AnnotationAttributes> attributesMap = new LinkedHashMap<>(8); @Override public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { String className = Type.getType(descriptor).getClassName(); this.annotationSet.add(className); return new AnnotationAttributesReadingVisitor(className, this.attributesMap); } @Override public boolean hasSuperClass() { return StringUtils.hasText(getSuperClassName()); } @Override public Set<String> getAnnotationTypes() { return this.annotationSet; } @Override public boolean hasAnnotation(String annotationType) { return this.annotationSet.contains(annotationType); } @Override public AnnotationAttributes getAnnotationAttributes(String annotationType) { return this.attributesMap.get(annotationType); } }

第三个类 AnnotationAttributesReadingVisitor 根据类 AnnotationMetadataReadingVisitor 传入的注解类型和属性集合,获取并填充注解对应的属性,代码实现如下:

/** * @author mghio * @since 2021-02-14 */ public class AnnotationAttributesReadingVisitor extends AnnotationVisitor { private final String annotationType; private final Map<String, AnnotationAttributes> attributesMap; private AnnotationAttributes attributes = new AnnotationAttributes(); public AnnotationAttributesReadingVisitor(String annotationType, Map<String, AnnotationAttributes> attributesMap) { super(Opcodes.ASM7); this.annotationType = annotationType; this.attributesMap = attributesMap; } @Override public void visit(String attributeName, Object attributeValue) { this.attributes.put(attributeName, attributeValue); } @Override public void visitEnd() { this.attributesMap.put(this.annotationType, this.attributes); } }

该类做的使用比较简单,就是当每访问当前注解的一个属性时,将其保存下来,最后当访问完成时以 K-V (key 为注解类型全名称,value 为注解对应的属性集合)的形式存入到 Map 中,比如,当我访问如下的类时:

/** * @author mghio * @since 2021-02-14 */ @Component(value = "orderService") public class OrderService { ... }

此时 AnnotationAttributesReadingVisitor 类的 visit(String, Object) 方法的参数即为当前注解的属性和属性的取值如下:

annotatoin-attributes-reading.png

至此我们已经完成了第二步中的前半部分的扫描指定包路径下的类并读取注解,虽然功能已经实现了,但是对应使用者来说还是不够友好,还需要关心一大堆相关的 Visitor 类,这里能不能再做一些封装呢?此时相信爱思考的你脑海里应该已经浮现了一句计算机科学界的名言:

计算机科学的任何一个问题,都可以通过增加一个中间层来解决。

仔细观察可以发现,以上读取类和注解相关信息的本质是元数据的读取,上文提到的 Resource 其实也是一中元数据,提供信息读取来源,将该接口命名为 MetadataReader,如下所示:

/** * @author mghio * @since 2021-02-14 */ public interface MetadataReader { Resource getResource(); ClassMetadata getClassMetadata(); AnnotationMetadata getAnnotationMetadata(); }

还需要提供该接口的实现,我们期望的最终结果是只要面向 MetadataReader 接口编程即可,只要传入 Resource 就可以获取 ClassMetadata 和 AnnotationMetadata 等信息,无需关心那些 visitor,将该实现类命名为 SimpleMetadataReader,其代码实现如下:

/** * @author mghio * @since 2021-02-14 */ public class SimpleMetadataReader implements MetadataReader { private final Resource resource; private final ClassMetadata classMetadata; private final AnnotationMetadata annotationMetadata; public SimpleMetadataReader(Resource resource) throws IOException { ClassReader classReader; try (InputStream is = new BufferedInputStream(resource.getInputStream())) { classReader = new ClassReader(is); } AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(); classReader.accept(visitor, ClassReader.SKIP_DEBUG); this.resource = resource; this.classMetadata = visitor; this.annotationMetadata = visitor; } @Override public Resource getResource() { return this.resource; } @Override public ClassMetadata getClassMetadata() { return this.classMetadata; } @Override public AnnotationMetadata getAnnotationMetadata() { return this.annotationMetadata; } }

在使用时只需要在构造 SimpleMetadataReader 传入对应的 Resource 即可,如下所示:

metadata-reader.png

到这里第二小步从字节码中读取注解的步骤已经完成了。

③ 根据读取到的 @Component 注解信息创建出对应的 BeanDefintion

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

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