元数据
元数据:数据的数据。比如Class就是一种元数据。Metadata在org.springframework.core.type包名下,还有用于读取的子包classreading也是重要知识点。此体系大致的类结构列出如下图:
可以看到顶层接口有两个:ClassMetadata和AnnotatedTypeMetadata
(一)Metadata
metata在org.springframework.core.type包名下,主要有以下相关接口和类
1.案例
案例:ZJJ_Spring_2020/05/20_11:27:04_iii6o |
---|
2.ClassMetadata接口
基本是Class相关的一致的,所以ClassMetadata实质是对Class的一种抽象和适配.
来看一下ClassMetadata的接口
// @since 2.5 public interface ClassMetadata { // 返回类名(注意返回的是最原始的那个className) String getClassName(); boolean isInterface(); // 是否是注解 boolean isAnnotation(); boolean isAbstract(); // 是否允许创建 不是接口且不是抽象类 这里就返回true了 boolean isConcrete(); boolean isFinal(); // 是否是独立的(能够创建对象的) 比如是Class、或者内部类、静态内部类 boolean isIndependent(); // 是否有内部类之类的东东 boolean hasEnclosingClass(); @Nullable String getEnclosingClassName(); boolean hasSuperClass(); @Nullable String getSuperClassName(); // 会把实现的所有接口名称都返回 具体依赖于Class#getSuperclass String[] getInterfaceNames(); // 基于:Class#getDeclaredClasses 返回类中定义的公共、私有、保护的内部类 String[] getMemberClassNames(); } |
---|
StandardClassMetadata
ClassMetadata的实现类StandardClassMetadata,构造函数中传入的参数是Class,方法基本是对Class的适配.
public class StandardClassMetadata implements ClassMetadata { private final Class<?> introspectedClass; public StandardClassMetadata(Class<?> introspectedClass) { Assert.notNull(introspectedClass, “Class must not be null”); this.introspectedClass = introspectedClass; } … public final Class<?> getIntrospectedClass() { return this.introspectedClass; } @Override public boolean isInterface() { return this.introspectedClass.isInterface(); } @Override public String[] getMemberClassNames() { LinkedHashSet for (Class<?> nestedClass : this.introspectedClass.getDeclaredClasses()) { memberClassNames.add(nestedClass.getName()); } return StringUtils.toStringArray(memberClassNames); } } |
---|
3.MethodsMetadata接口
用来描述java.lang.reflect.Method。
它是子接口,主要增加了从Class里获取到MethodMetadata们的方法:
// @since 2.1 可以看到它出现得更早一些 public interface MethodsMetadata extends ClassMetadata { // 返回该class所有的方法 Set // 方法指定方法名的方法们(因为有重载嘛~) Set } |
---|
名字上请不要和MethodMetadata搞混了,MethodMetadata是AnnotatedTypeMetadata的子接口,代表具体某一个Type(方法上的注解);而此类是个ClassMetadata,它能获取到本类里所有的方法Method(MethodMetadata)~
4.AnnotatedTypeMetadata
对注解元素的封装适配
什么叫注解元素(AnnotatedElement)?比如我们常见的Class、Method、Constructor、Parameter等等都属于它的子类都属于注解元素。简单理解:只要能在上面标注注解都属于这种元素。Spring4.0新增的这个接口提供了对注解统一的、便捷的访问,使用起来更加的方便高效了。
// @since 4.0 public interface AnnotatedTypeMetadata { // 此元素是否标注有此注解~~~~ // annotationName:注解全类名 boolean isAnnotated(String annotationName); // 这个就厉害了:取得指定类型注解的所有的属性 - 值(k-v) // annotationName:注解全类名 // classValuesAsString:若是true表示 Class用它的字符串的全类名来表示。这样可以避免Class被提前加载 @Nullable Map @Nullable Map // 参见这个方法的含义:AnnotatedElementUtils.getAllAnnotationAttributes @Nullable MultiValueMap @Nullable MultiValueMap } |
---|
它的继承树如下:
两个子接口相应的都提供了标准实现以及基于ASM的Visitor模式实现。
ASM 是一个通用的 Java 字节码操作和分析框架。它可以用于修改现有类或直接以二进制形式动态生成类。 ASM 虽然提供与其他 Java 字节码框架如 Javassist,CGLIB类似的功能,但是其设计与实现小而快,且性能足够高。
Spring 直接将 ASM 框架核心源码内嵌于 Spring-core中,目前`Spring 5.1使用ASM 7 版本。
StandardMethodMetadata是基于反射的标准实现.
MethodMetadataReadingVisitor是基于ASM的实现的,继承自ASM``的org.springframework.asm.MethodVisitor采用Visitor的方式读取到元数据。
5.AnnotationMetadata
这是理解Spring注解编程的必备知识,它是ClassMetadata和AnnotatedTypeMetadata的子接口,具有两者共同能力,并且新增了访问注解的相关方法。可以简单理解为它是对注解的抽象。
经常这么使用得到注解里面所有的属性值:
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annoMetadata, annType);
// @since 2.5 public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata { //拿到当前类上所有的注解的全类名(注意是全类名) Set // 拿到指定的注解类型 //annotationName:注解类型的全类名 Set // 是否包含指定注解 (annotationName:全类名) boolean hasAnnotation(String annotationName); //这个厉害了,用于判断注解类型自己是否被某个元注解类型所标注 //依赖于AnnotatedElementUtils#hasMetaAnnotationTypes boolean hasMetaAnnotation(String metaAnnotationName); // 类里面只有有一个方法标注有指定注解,就返回true //getDeclaredMethods获得所有方法, AnnotatedElementUtils.isAnnotated是否标注有指定注解 boolean hasAnnotatedMethods(String annotationName); // 返回所有的标注有指定注解的方法元信息。注意返回的是MethodMetadata 原理基本同上 Set } |
---|
StandardAnnotationMetadata
继承了StandardClassMetadata,很明显关于ClassMetadata的实现部分就交给此父类了,自己只关注于AnnotationMetadata接口的实现。
// @since 2.5 public class StandardAnnotationMetadata extends StandardClassMetadata implements AnnotationMetadata { // 很显然它是基于标准反射类型:java.lang.annotation.Annotation // this.annotations = introspectedClass.getAnnotations() private final Annotation[] annotations; private final boolean nestedAnnotationsAsMap; … // 获取本Class类上的注解的元注解们 @Override public Set return (this.annotations.length > 0 ? AnnotatedElementUtils.getMetaAnnotationTypes(getIntrospectedClass(), annotationName) : Collections.emptySet()); } @Override public boolean hasAnnotation(String annotationName) { for (Annotation ann : this.annotations) { if (ann.annotationType().getName().equals(annotationName)) { return true; } } return false; } … } |
---|
6.AnnotationMetadataReadingVisitor
继承自ClassMetadataReadingVisitor,同样的ClassMetadata部分实现交给了它。
说明:ClassMetadataReadingVisitor是org.springframework.core.type.classreading包下的类,同包的还有我下面重点讲述的MetadataReader。此实现类最终委托给AnnotationMetadataReadingVisitor来做的,而它便是ClassMetadataReadingVisitor的子类(MetadataReader的底层实现就是它,使用的ASM的ClassVisitor模式读取元数据)。
(二)MetadataReader
你是否有疑问:为何Spring要提供一个标准实现和一个ASM的实现呢?这里就能给你答案。
此接口是一个访问ClassMetadata等的简单门面,实现是委托给org.springframework.asm.ClassReader、ClassVisitor来处理的,它不用把Class加载进JVM就可以拿到元数据,因为它读取的是资源:Resource,这是它最大的优势所在。
public interface MetadataReader { Resource getResource(); ClassMetadata getClassMetadata(); AnnotationMetadata getAnnotationMetadata(); } |
---|
1.SimpleMetadataReader
它是基于ASM的org.springframework.asm.ClassReader的简单实现。请注意:此类是非public的,而是default包访问权限。
final class SimpleMetadataReader implements MetadataReader { private final Resource resource; private final ClassMetadata classMetadata; private final AnnotationMetadata annotationMetadata; SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException { InputStream is = new BufferedInputStream(resource.getInputStream()); ClassReader classReader; try { classReader = new ClassReader(is); } catch (IllegalArgumentException ex) { throw new NestedIOException(“ASM ClassReader failed to parse class file - “ + “probably due to a new Java class file version that isn’t supported yet: “ + resource, ex); } finally { is.close(); } AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(classLoader); classReader.accept(visitor, ClassReader.SKIP_DEBUG); this.annotationMetadata = visitor; this.classMetadata = visitor; this.resource = resource; } … } |
---|
2.MethodsMetadataReader
子接口,新增接口方法:获取到本类所有的方法元数据们.
public interface MethodsMetadataReader extends MetadataReader { MethodsMetadata getMethodsMetadata(); … } |
---|
它所有的实现都是委托给静态内部类MethodsMetadataReadingVisitor去做的,它继承自上面的AnnotationMetadataReadingVisitor并且实现了接口MethodsMetadata的相关方法。
它的唯一实现类DefaultMethodsMetadataReader的访问权限也是包级别非public,略。
(三)MetadataReaderFactory
MetadataReader的实现都并未public暴露出来,所以我们若想得到它的实例,就只能通过此工厂。
public interface MetadataReaderFactory { MetadataReader getMetadataReader(String className) throws IOException; MetadataReader getMetadataReader(Resource resource) throws IOException; } |
---|
1.SimpleMetadataReaderFactory
利用ResourceLoader的简单实现,加载进资源后,new SimpleMetadataReader(resource)交给此实例分析即可。
public class SimpleMetadataReaderFactory implements MetadataReaderFactory { private final ResourceLoader resourceLoader; @Override public MetadataReader getMetadataReader(String className) throws IOException { try { String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX; Resource resource = this.resourceLoader.getResource(resourcePath); return getMetadataReader(resource); } catch (FileNotFoundException ex) { … } } @Override public MetadataReader getMetadataReader(Resource resource) throws IOException { return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader()); } } |
---|
2.CachingMetadataReaderFactory
它继承自SimpleMetadataReaderFactory,没有其它特殊的,就是提供了缓存能力private Map
因为有了它,所以SimpleMetadataReaderFactory就不需要被直接使用了,用它代替。Spring内自然也使用的便是效率更高的它喽~
因为MetadataReader的实现类都是包级别的访问权限,所以它的实例只能来自工厂
案例:ZJJ_Spring_2020/05/20_12:24:14_nsife |
---|
3.MethodsMetadataReaderFactory
它继承自SimpleMetadataReaderFactory,唯一区别是它生产的是一个MethodsMetadataReader(DefaultMethodsMetadataReader),从而具有了读取MethodsMetadata的能力。
此类可认为从没有被Spring内部使用过,暂且可忽略(spring-data工程有用)
Factory工厂的实现都是非常简单的,毕竟只是为了生产一个实例而已。