Spring元数据Metadata的使用,注解编程之AnnotationMetadata,ClassMetadata、MetadataReaderFactory【享学Spring】(上)

简介: Spring元数据Metadata的使用,注解编程之AnnotationMetadata,ClassMetadata、MetadataReaderFactory【享学Spring】(上)

前言


Spring在2.0的时候就支持了基于XML Schema的扩展机制,让我们可以自定义的对xml配置文件进行扩展(四大步骤,有兴趣的可以自己学习),比如鼎鼎大名的Dubbo它就扩展了xml,用它来引入服务或者导出服务。

随着Spring3.0+的发展,xml慢慢的淡出了我们的视野,特别是Spring Boot的流行让xml彻底消失,所有的xml配置都使用注解的方式进行了代替。有的人说注解编程源码难度是 XML 扩展好几倍,其实我并不这么认为,本文就着眼于大多数小伙伴比较费解的元数据(Metadata)进行分析,给深入理解注解编程铺路。


元数据


元数据:数据的数据。比如Class就是一种元数据。Metadata在org.springframework.core.type包名下,还有用于读取的子包classreading也是重要知识点。此体系大致的类结构列出如下图:


image.png


image.png


可以看到顶层接口有两个:ClassMetadata和AnnotatedTypeMetadata


注解上的注解,Spring将其定义为元注解(meta-annotation),如 @Component标注在 @Service上,@Component就被称作为元注解。后面我们就将注解的注解称为元注解。


ClassMetadata:对Class的抽象和适配


此接口的所有方法,基本上都跟Class有关。

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

它的继承树如下:


image.png


StandardClassMetadata


基于Java标准的(Standard)反射实现元数据的获取。


// @since 2.5
public class StandardClassMetadata implements ClassMetadata {
  // 用于内省的Class类
  private final Class<?> introspectedClass;
  // 唯一构造函数:传进来的Class,作为内部的内省对象
  public StandardClassMetadata(Class<?> introspectedClass) {
    Assert.notNull(introspectedClass, "Class must not be null");
    this.introspectedClass = introspectedClass;
  }
  ... // 后面所有的方法实现,都是基于introspectedClass,类似代理模式。举例如下:
  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);
  }
}


它有个非常重要的子类:StandardAnnotationMetadata它和注解密切相关,在文章下半部分重点分析。


MethodsMetadata:新增访问方法元数据的接口


它是子接口,主要增加了从Class里获取到MethodMetadata们的方法:


// @since 2.1 可以看到它出现得更早一些
public interface MethodsMetadata extends ClassMetadata {
  // 返回该class所有的方法
  Set<MethodMetadata> getMethods();
  // 方法指定方法名的方法们(因为有重载嘛~)
  Set<MethodMetadata> getMethods(String name);
}


名字上请不要和MethodMetadata搞混了,MethodMetadata是AnnotatedTypeMetadata的子接口,代表具体某一个Type(方法上的注解);而此类是个ClassMetadata,它能获取到本类里所有的方法Method(MethodMetadata)~

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<String, Object> getAnnotationAttributes(String annotationName);
  @Nullable
  Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString);
  // 参见这个方法的含义:AnnotatedElementUtils.getAllAnnotationAttributes
  @Nullable
  MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName);
  @Nullable
  MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString);
}


它的继承树如下:


image.png



两个子接口相应的都提供了标准实现以及基于ASM的Visitor模式实现。


ASM 是一个通用的 Java 字节码操作和分析框架。它可以用于修改现有类或直接以二进制形式动态生成类。 ASM 虽然提供与其他 Java 字节码框架如 Javassist,CGLIB类似的功能,但是其设计与实现小而快,且性能足够高。


Spring 直接将 ASM 框架核心源码内嵌于 Spring-core中,目前`Spring 5.1使用ASM 7 版本。

相关文章
|
28天前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
170 73
|
2天前
|
XML 监控 前端开发
Spring Boot中的WebFlux编程模型
Spring WebFlux 是 Spring Framework 5 引入的响应式编程模型,基于 Reactor 框架,支持非阻塞异步编程,适用于高并发和 I/O 密集型应用。本文介绍 WebFlux 的原理、优势及在 Spring Boot 中的应用,包括添加依赖、编写响应式控制器和服务层实现。WebFlux 提供高性能、快速响应和资源节省等优点,适合现代 Web 应用开发。
41 15
|
23天前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
51 21
|
6天前
|
人工智能 Java API
阿里云工程师跟通义灵码结伴编程, 用Spring AI Alibaba来开发 AI 答疑助手
本次分享的主题是阿里云工程师跟通义灵码结伴编程, 用Spring AI Alibaba来开发 AI 答疑助手,由阿里云两位工程师分享。
阿里云工程师跟通义灵码结伴编程, 用Spring AI Alibaba来开发 AI 答疑助手
|
28天前
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
|
1月前
|
Java Spring
一键注入 Spring 成员变量,顺序编程
介绍了一款针对Spring框架开发的插件,旨在解决开发中频繁滚动查找成员变量注入位置的问题。通过一键操作(如Ctrl+1),该插件可自动在类顶部添加`@Autowired`注解及其成员变量声明,同时保持光标位置不变,有效提升开发效率和代码编写流畅度。适用于IntelliJ IDEA 2023及以上版本。
一键注入 Spring 成员变量,顺序编程
|
28天前
|
Java Spring
【Spring配置】idea编码格式导致注解汉字无法保存
问题一:对于同一个项目,我们在使用idea的过程中,使用汉字注解完后,再打开该项目,汉字变成乱码问题二:本来a项目中,汉字注解调试好了,没有乱码了,但是创建出来的新的项目,写的注解又成乱码了。
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
194 2
|
2月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
72 2
|
2月前
|
前端开发 Java 开发者
Spring MVC中的控制器:@Controller注解全解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序控制层的核心。它不仅简化了控制器的定义,还提供了灵活的请求映射和处理机制。本文将深入探讨`@Controller`注解的用法、特点以及在实际开发中的应用。
143 0