在Spring源码中有很多场景会去解析类的信息,比如类名、类中的方法、类上的注解,这些都可以称之为类的元数据,在Spring中对类的元数据做了抽象,并提供了一些工具类。
MetadataReader表示类的元数据读取器,默认实现类为SimpleMetadataReader
测试代码如下:
// 自定义注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Pan
public @interface Qiu {
}
// 目标类
@JsonFormat
@Service
@Transactional(rollbackFor = Exception.class)
@Qiu
@Generated
public class MobianServiceImpl implements MobianService {
....
}
public class Test {
public static void main(String[] args) throws IOException, IOException {
SimpleMetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory();
// 使用工厂构建一个metadataReader读取器
MetadataReader metadataReader = readerFactory.getMetadataReader("pers.mobian.testtransactional.service.MobianServiceImpl");
System.out.println("-----获取类的基本信息----");
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 判断是否是接口
System.out.println(classMetadata.isInterface());
// 判断是否是抽象类
System.out.println(classMetadata.isAbstract());
// 获取类的名字
System.out.println(classMetadata.getClassName());
System.out.println("-----获取类的注解信息----");
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 类上注解的元注解是否含有对应的注解(即针对注解的父注解)
System.out.println(annotationMetadata.hasMetaAnnotation(Pan.class.getName()));
// 类上是否有对应的注解
System.out.println(annotationMetadata.hasAnnotation(Pan.class.getName()));
for (String annotationType : annotationMetadata.getAnnotationTypes()) {
// 打印类上的注解
System.out.println(annotationType);
}
System.out.println("-----获取类的资源信息----");
Resource resource = metadataReader.getResource();
// 打印类的名字
System.out.println(resource.getFilename());
}
}
打印结果:
注意:
1、hasMetaAnnotation可以理解为是用来判断注解的父注解信息,hasAnnotation是用来判断当前类的注解信息。上面的测试案例中,目标类没有@Pan这个注解,但是修饰类的@Qiu的注解被@Pan注解修饰,所以前者打印true,后者打印false
// 使用元方法读取器读取注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//
System.out.println(annotationMetadata.hasMetaAnnotation(Pan.class.getName()));
System.out.println(annotationMetadata.hasAnnotation(Pan.class.getName()));
2、在获取类上注解的时候,类上的注解需要被@Retention(RetentionPolicy.RUNTIME)注解修饰才能被扫描出来。我的理解是,由于该工具类的底层是使用ASM技术去获取类的class文件信息,继而完成信息的获取,如果我Retention设置为CLASS或者SOURCE,其底层在使用ASM技术去JVM中获取对应信息时,获取不到对应的class文件,以至于扫描不到对应的注解信息。
for (String annotationType : annotationMetadata.getAnnotationTypes()) {
// 打印类上的注解
System.out.println(annotationType);
}