AnnotationMetadata、 MethodMetadata

您所在的位置:网站首页 metadata注解 AnnotationMetadata、 MethodMetadata

AnnotationMetadata、 MethodMetadata

2023-12-19 14:30| 来源: 网络整理| 查看: 265

元数据:数据的数据 比如Class就是一种元数据 Metadata在org.springframework.core.type包名下,该包内类不多,主要有以下相关接口和类: 所以我们看到顶层接口有两个:ClassMetadata和AnnotatedTypeMetadata

顶层接口:ClassMetadata和AnnotatedTypeMetadata 一、ClassMetadata ClassMetadata:对Class的封装适配,使用它时,并不要求该Bean已经被加载~它的所有方法,基本上都跟Class有关。

// underlying class:基础的class 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

public class StandardClassMetadata implements ClassMetadata { private final Class introspectedClass; // 就一个构造函数,传进来的Class,作为内部的内省对象 public StandardClassMetadata(Class introspectedClass) { Assert.notNull(introspectedClass, "Class must not be null"); this.introspectedClass = introspectedClass; } ... 后面所有的方法实现,都是基于introspectedClass,举例如下: /** * Return the underlying Class. */ public final Class getIntrospectedClass() { return this.introspectedClass; } @Override public boolean isInterface() { return this.introspectedClass.isInterface(); } @Override public String[] getMemberClassNames() { LinkedHashSet memberClassNames = new LinkedHashSet(4); for (Class nestedClass : this.introspectedClass.getDeclaredClasses()) { memberClassNames.add(nestedClass.getName()); } return StringUtils.toStringArray(memberClassNames); } }

二、AnnotatedTypeMetadata AnnotatedTypeMetadata:对AnnotatedElement的封装适配

它没有Standard的实现(毕竟AnnotatedElement也是接口,没办法做基础实现的),但是它有两个非常重要的子接口:AnnotationMetadata和 MethodMetadata 这两个接口是Spring内部的直接运用。 java的反射包里有一个接口AnnotatedElement,Spring对该接口做了进一步的封装。虽没直接继承的实现类,但该接口的实现都是调用工具类 AnnotatedElementUtils的静态方法实现的。平时在处理注解的也可以用AnnotatedElementUtils或者AnnotationUtils提供的方法,这两个工具类会对 结果进行缓存,稍微减少重复读取时反射调用的资源消耗。这两个工具方法的实现比较复杂,但public的静态方法的方法名都尽量做到了所见即所得,也有 比较详细的注释,需要注意的是get和find两者语义的不同,get的查找范围仅限定于本身,而find则会在父类、实现的接口(对类而言);父类的方法、接 口的方法、桥接方法(重载泛型方法会出现)查找。

二级接口AnnotationMetadata和MethodMetadata 这两个元数据接口,在Spring内部非常常用,需要掌握。前者Spring2.5就有了,后者Spring3.0才有的

(1)AnnotationMetadata:对Class相关的多个注解进行获取和判断

public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata { //拿到Class上标注的所有注解,依赖于Class#getAnnotations Set getAnnotationTypes(); // 拿到所有的元注解信息AnnotatedElementUtils#getMetaAnnotationTypes //annotationName:注解类型的全类名 Set getMetaAnnotationTypes(String annotationName); // 是否包含指定注解 (annotationName:全类名) boolean hasAnnotation(String annotationName); //这个厉害了,依赖于AnnotatedElementUtils#hasMetaAnnotationTypes boolean hasMetaAnnotation(String metaAnnotationName); // 类里面只有有一个方法标注有指定注解,就返回true //getDeclaredMethods获得所有方法, AnnotatedElementUtils.isAnnotated是否标注有指定注解 boolean hasAnnotatedMethods(String annotationName); // 注意返回的是MethodMetadata 原理基本同上 // .getDeclaredMethods和AnnotatedElementUtils.isAnnotated 最后吧Method转为MethodMetadata Set getAnnotatedMethods(String annotationName); }

主要实现类:StandardAnnotationMetadata 、AnnotationMetadataReadingVisitor StandardAnnotationMetadata:扩展了StandardClassMetadata增加对注解的支持 它继承了StandardClassMetadata,然后实现了AnnotationMetadata来提供对注解的主持扩展。

public class StandardAnnotationMetadata extends StandardClassMetadata implements AnnotationMetadata { // 持有对本类所有注解的引用 private final Annotation[] annotations; private final boolean nestedAnnotationsAsMap; public StandardAnnotationMetadata(Class introspectedClass, boolean nestedAnnotationsAsMap) { super(introspectedClass); this.annotations = introspectedClass.getAnnotations(); this.nestedAnnotationsAsMap = nestedAnnotationsAsMap; } ...// 它实现了所有AnnotationMetadata 接口的方法 因为实现很简单 此处就省略掉了 }

(2)MethodMetadata:方法的元数据

// 基本上是代理了Method introspectedMethod; public interface MethodMetadata extends AnnotatedTypeMetadata { // 方法名称 String getMethodName(); // 此方法所属类的全类名 String getDeclaringClassName(); // 方法返回值的全类名 String getReturnTypeName(); // 是否是抽象方法 boolean isAbstract(); // 是否是静态方法 boolean isStatic(); //是否是final方法 boolean isFinal(); // 是否可以被复写(不是静态、不是final、不是private的 就表示可以被复写) boolean isOverridable(); }

主要实现类:StandardMethodMetadata、MethodMetadataReadingVisitor

StandardMethodMetadata:只实现了MethodMetadata,属于标准实现,需要注意的是,它还得实现AnnotatedTypeMetadata这个接口里的所有方法

public class StandardMethodMetadata implements MethodMetadata { // 持有方法的引用:内省方法 private final Method introspectedMethod; private final boolean nestedAnnotationsAsMap; public StandardMethodMetadata(Method introspectedMethod, boolean nestedAnnotationsAsMap) { Assert.notNull(introspectedMethod, "Method must not be null"); this.introspectedMethod = introspectedMethod; this.nestedAnnotationsAsMap = nestedAnnotationsAsMap; } ... // 实现都非常简单,此处省略 说说AnnotatedTypeMetadata接口的实现 @Override public boolean isAnnotated(String annotationName) { return AnnotatedElementUtils.isAnnotated(this.introspectedMethod, annotationName); } @Override @Nullable public Map getAnnotationAttributes(String annotationName) { return getAnnotationAttributes(annotationName, false); } @Override @Nullable public Map getAnnotationAttributes(String annotationName, boolean classValuesAsString) { return AnnotatedElementUtils.getMergedAnnotationAttributes(this.introspectedMethod, annotationName, classValuesAsString, this.nestedAnnotationsAsMap); } @Override @Nullable public MultiValueMap getAllAnnotationAttributes(String annotationName) { return getAllAnnotationAttributes(annotationName, false); } // 这个和getMergedAnnotationAttributes有关 @Override @Nullable public MultiValueMap getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) { return AnnotatedElementUtils.getAllAnnotationAttributes(this.introspectedMethod, annotationName, classValuesAsString, this.nestedAnnotationsAsMap); } }

最后关于AnnotationMetadataReadingVisitor和MethodMetadataReadingVisitor,它俩都实现了xxxVisitor接口的,和Spring中处理ASM技术有关

三、MetadataReader接口 它的默认实现SimpleMetadataReader,内部实现原理就是基于AnnotationMetadataReadingVisitor使用ASM相关的,该接口对Class的元数据做了一个get方法的封装,方便一次性获取所有需要的数据。

public interface MetadataReader { // 返回此Class来自的资源(创建的时候需要指定此资源,然后交给`AnnotationMetadataReadingVisitor`去处理) Resource getResource(); // ClassMeta,实现为通过`AnnotationMetadataReadingVisitor`中获取 ClassMetadata getClassMetadata(); // 注解元信息 也是通过`AnnotationMetadataReadingVisitor`获取 AnnotationMetadata getAnnotationMetadata(); }

接口的实现是包类外部是不可见的,就不记录了。获取实例是通过工厂类获取的。Spring提供了两个工厂类的实现:SimpleMetadataReaderFactory、CachingMetadataReaderFactory,这两个工厂类实现类工厂接口MetadataReaderFactory:

public interface MetadataReaderFactory { /** * Obtain a MetadataReader for the given class name. * @param className the class name (to be resolved to a ".class" file) * @return a holder for the ClassReader instance (never {@code null}) * @throws IOException in case of I/O failure */ MetadataReader getMetadataReader(String className) throws IOException; /** * Obtain a MetadataReader for the given resource. * @param resource the resource (pointing to a ".class" file) * @return a holder for the ClassReader instance (never {@code null}) * @throws IOException in case of I/O failure */ MetadataReader getMetadataReader(Resource resource) throws IOException; }

顾名思义,CachingMetadataReaderFactory在读取的时候会做一次缓存,默认缓存256和实例,淘汰规则是FIFO。

总结 Metadata在框架中往往是个很重要的概念,不仅仅是Spring,MyBatis、Hibernate等流行框架中都有类似的元数据的概念。它能让我们更容器的操控一些底层的描述性属性,从而做不同的逻辑判断处理。从而就能使得框架有更强的包容能力

元数据JDK提供的和Spring提供的还是不太一样的。但是Spring大部分都是基于JDK的封装和适配,然后给到一个Spring自己内部的类。这也是Spring在到处都是适配器模式的典型应用



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3