【小家Spring】聊聊Spring中的那些【Metadata】,举例讲解:AnnotationMetadata、 MethodMetadata

版权声明: https://blog.csdn.net/f641385712/article/details/88765470

每篇一句

不要担心你此次此刻的付出得不到回报,因为你现在的付出是为了扎根

相关阅读

【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(一)
【小家Spring】Spring IOC容器启动流程 AbstractApplicationContext#refresh()方法源码分析(二),Spring容器启动/刷新的完整总结

【小家Spring】Spring提供的多个注解相关的工具类:AnnotationUtils、AnnotatedElementUtils、AnnotationConfigUtils…

前言

元数据:数据的数据 比如Class就是一种元数据

Metadataorg.springframework.core.type包名下,该包内类不多,主要有以下相关接口和类:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

所以我们看到顶层接口有两个:ClassMetadataAnnotatedTypeMetadata

顶层接口:ClassMetadataAnnotatedTypeMetadata

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

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<String> memberClassNames = new LinkedHashSet<>(4);
		for (Class<?> nestedClass : this.introspectedClass.getDeclaredClasses()) {
			memberClassNames.add(nestedClass.getName());
		}
		return StringUtils.toStringArray(memberClassNames);
	}
}

AnnotatedTypeMetadata:对AnnotatedElement的封装适配

它没有Standard的实现(毕竟AnnotatedElement也是接口,没办法做基础实现的),但是它有两个非常重要的子接口:AnnotationMetadataMethodMetadata 这两个接口是Spring内部的直接运用

二级接口AnnotationMetadataMethodMetadata

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

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

public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {

	//拿到Class上标注的所有注解,依赖于Class#getAnnotations
	Set<String> getAnnotationTypes();

	// 拿到所有的元注解信息AnnotatedElementUtils#getMetaAnnotationTypes
	//annotationName:注解类型的全类名
	Set<String> 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<MethodMetadata> getAnnotatedMethods(String annotationName);
}

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();
}

主要实现类

主要实现类有:StandardAnnotationMetadataStandardMethodMetadataAnnotationMetadataReadingVisitorMethodMetadataReadingVisitor。先聊聊标准实现(前两个)

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 接口的方法 因为实现很简单 此处就省略掉了
	
}
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<String, Object> getAnnotationAttributes(String annotationName) {
		return getAnnotationAttributes(annotationName, false);
	}
	@Override
	@Nullable
	public Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
		return AnnotatedElementUtils.getMergedAnnotationAttributes(this.introspectedMethod,
				annotationName, classValuesAsString, this.nestedAnnotationsAsMap);
	}
	@Override
	@Nullable
	public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName) {
		return getAllAnnotationAttributes(annotationName, false);
	}
	// 这个和getMergedAnnotationAttributes有关
	@Override
	@Nullable
	public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) {
		return AnnotatedElementUtils.getAllAnnotationAttributes(this.introspectedMethod,
				annotationName, classValuesAsString, this.nestedAnnotationsAsMap);
	}
	
}

最后关于AnnotationMetadataReadingVisitorMethodMetadataReadingVisitor,它俩都实现了xxxVisitor接口的,和Spring中处理ASM技术有关,不在本文讨论的范围之内,暂且略过。

Spring内部使用得字节码技术,比如SimpleMetadataReaderCachingMetadataReaderFactory等等

MetadataReader接口

它是一个访问ClassMetadata等的简单门面。它的唯一实现SimpleMetadataReader内部实现原理就是基于AnnotationMetadataReadingVisitor使用ASM相关的

public interface MetadataReader {

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

}

总结

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

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

最后,关于Spring中ASM技术处理元数据以及其余的应用场景,肯定会有专门的大篇幅来讲述,因为那将是一个很大的话题,也是一个很难的专题

知识交流

在这里插入图片描述
若群二维码失效,请加微信号(或者扫描下方二维码):fsx641385712。
并且备注:“java入群” 字样,会手动邀请入群

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/f641385712/article/details/88765470