这个方法,是从spring 源码里摘抄的,在内部实现中,基本就这个样子:
我这个版本是4.0,在:org.springframework.bootstrap.sample.Test#recusivelyCollectMetaAnnotations public static void getAnnotationByClass(String className) throws ClassNotFoundException { Class<?> clazz = Class.forName(className); Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>(); for (Annotation metaAnnotation : clazz.getAnnotations()) { recusivelyCollectMetaAnnotations(metaAnnotationTypeNames, metaAnnotation); } } private static void recusivelyCollectMetaAnnotations(Set<String> visited, Annotation annotation) { if (visited.add(annotation.annotationType().getName())) { for (Annotation metaMetaAnnotation : annotation.annotationType().getAnnotations()) { //递归 recusivelyCollectMetaAnnotations(visited, metaMetaAnnotation); } } }我试了下,这个方法在新版本里,方法名变了,核心还是差不多,spring 5.1.9可以看这个类:
org.springframework.core.type.classreading.AnnotationAttributesReadingVisitor#recursivelyCollectMetaAnnotations
输出如下:
java.lang.annotation.Documented
java.lang.annotation.Retention
java.lang.annotation.Target
org.springframework.stereotype.Controller
org.springframework.stereotype.Component
这个是我自己实现的,要复杂一些,当然,是有理由的:
import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; public static void main(String[] args) throws IOException, ClassNotFoundException { SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory(); LinkedHashSet<String> result = new LinkedHashSet<>(); getAnnotationSet(result, "org.springframework.test.TestController", simpleMetadataReaderFactory); } public static void getAnnotationSet(LinkedHashSet<String> result, String className, SimpleMetadataReaderFactory simpleMetadataReaderFactory) throws IOException { boolean contains = result.add(className); if (!contains) { return; } MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader(className); AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); Set<String> annotationTypes = annotationMetadata.getAnnotationTypes(); if (!CollectionUtils.isEmpty(annotationTypes)) { for (String annotationType : annotationTypes) { // 递归 getAnnotationSet(result, annotationType, simpleMetadataReaderFactory); } } }估计有的同学要骂人了,取个注解,搞一堆莫名其妙的工具类干嘛?因为,spring就是这么玩的啊,方法1,是spring的实现,不假。但是,那个已经是最内层了,人家外边还封装了一堆,封装出来,基本就是方法2看到的那几个类。
spring抽象出的注解获取的核心接口大家看看,就是下面这个,类图如下:
其大致的功能,看下图就知道了:
这个接口,一共2个实现,简单来说,一个是通过传统的反射方式来获取这些信息,一个是通过asm的方式。
两者的优劣呢,大家可以看看小马哥的书,里面提到的是,asm方式的性能,远高于反射实现,因为无需加载class,直接解析class文件的字节码。
我们这里也是主要讲asm方式的实现,大家看到了上面这个asm实现的类,叫:AnnotationMetadataReadingVisitor,它的类结构,如下:
从上图可以大致知道,其继承了ClassMetadataReadingVisitor,这个类,负责去实现ClassMetaData接口;它自己呢,就自己负责实现AnnotationMetadata接口。
我们呢,不是很关心类的相关信息,只聚焦注解的获取。
AnnotationMetadataReadingVisitor如何实现AnnotationMetadata接口AnnotationMetadata接口,我们最关注的就是下面这2个方法:
// 获取直接注解在当前class上的注解 Set<String> getAnnotationTypes(); // 获取某个直接注解的元注解,比如你这里传个controller进去,就能给你拿到controller这个注解的元注解 Set<String> getMetaAnnotationTypes(String annotationType);大家可以看到,它呢,给了2个方法,而不是一个方法来获取所有,可能有其他考虑吧,我们接着看。
getAnnotationTypes的实现这个方法,获取直接注解在target class上的注解。
那看看这个方法在AnnotationMetadataReadingVisitor的实现吧:
public Set<String> getAnnotationTypes() { return this.annotationSet; }