上篇文章研究 Spring XML Schema 扩展进制,这段时候一直研究 Spring 注解编程的原理。原本以为有了之前研究基础,可以很快理解注解编程原理。没想到这个过程非常困难,注解编程源码难度是 XML 扩展好几倍。o(╥﹏╥)o。


Spring 框架中有很多可用的注解,其中有一类注解称模式注解(Stereotype Annotations),包括 @Component, @Service,@Controller,@Repository 等。只要在相应的类上标注这些注解,就能成为 Spring 中组件(Bean)。

需要配置开启自动扫描。如在 XML 中配置 <context:component-scan base-package="xxx.xxx.xx"/>` 或使用注解 @ComponentScan。

从最终的效果上来看,@Component, @Service,@Controller,@Repository 起到的作用完全一样,那为何还需要多个不同的注解?

从官方 wiki 我们可以看到原因。

A stereotype annotation is an annotation that is used to declare the role that a component plays within the application. For example, the @Repository annotation in the Spring Framework is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO).

不同的模式注解虽然功能相同,但是代表含义却不同。

标注@Controller 注解,这类组件就可以表示为 WEB 控制层 ,处理各种 HTTP 交互。标注 @Service 可以表示为内部服务层 ,处理内部服务各种逻辑。而 @Repository 可以代表示为数据控制层,代表数据库增删改查动作。

这样一来不同模式注解带来了不同的含义,清晰将服务进行分层。

除了上面的作用,特定的模式注解,Spring 可能会在未来增加额外的功能语义。如现在 @Repository 注解,可以增加异常的自动转换功能。

所以,对于分层服务最好使用各自特定语义的模式注解,如 WEB 层就使用 @Controller注解。

模式注解原理

在 Spring 中任何标注 @Component 的组件都可以成为扫描的候选对象。另外任何使用 @Component 标注的注解,如 @Service,当其标注组件时,也能被当做扫描的候选对象。。

@Component is a generic stereotype for any Spring-managed component. Any component annotated with @Component is a candidate for component scanning. Similarly, any component annotated with an annotation that is itself meta-annotated with @Component is also a candidate for component scanning. For example, @Service is meta-annotated with @Component.

如果想使自定义的注解也能如 @Service 注解功能一样,只要在自定义注解上标注 @Component 就可以。

AnnotationMetadata

从上面文档看出只要在类上存在 @Component注解,即使存在于注解的注解上,Spring 都将能其成为候选组件。

注解上的注解 Spring 将其定义为元注解(meta-annotation),如 @Component标注在 @Service上,@Component 就被称作为元注解。后面我们就将注解的注解称为元注解。
A meta-annotation is an annotation that is declared on another annotation. An annotation is therefore meta-annotated if it is annotated with another annotation. For example, any annotation that is declared to be documented is meta-annotated with @Documented from thejava.lang.annotation package.

那么对于一个类是否可以成为 Spring 组件,需要判断这个类是否包含 @Component 注解,或者类上元注解中是否包含 @Component

在 Spring 中可以通过 MetadataReader 获取 ClassMetadata 以及 AnnotationMetadata,然后获取相应元数据。

ClassMetadata 可以获取类的各种元数据,比如类名,接口等。

AnnotationMetadata 可以获取当前类上注解的元数据,如注解名字,以及元注解信息等。

所以只要获取到 AnnotationMetadata,就可以判断是否存在 @Component。判断方式如下

获取 AnnotationMetadata

这里我们从 XML 配置开启扫描开始讲起。

<context:component-scan base-package="xxx.xxx.xx"/>

首先在 META-INF 下查找 spring.handles 文件。

不明白小伙伴们可以查看上一篇文章 缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制

context 标签在 ContextNamespaceHandler 注册 XML 解析器。在ContextNamespaceHandler中其使用了 ComponentScanBeanDefinitionParser真正解析 XML。

ComponentScanBeanDefinitionParser#parse 方法中,首先获取 XML 中配置 base-package属性,获取扫描的范围,然后调用 ClassPathBeanDefinitionScanner#doScan 获取 base-package 所有 BeanDefinition

doScan 方法中最终会调用ClassPathScanningCandidateComponentProvider#scanCandidateComponents 获取扫描范围内所有 BeanDefinition

scanCandidateComponents 中首先获取扫描包范围内资源对象,然后迭代从可读取资源对象中MetadataReaderFactory#getMetadataReader(resource)获取MetadataReader` 对象。

上文已经讲到 MetadataReader 对象作用,这里查看如何使用MetadataReader 进行判断。

筛选组件

isCandidateComponent方法中将会传入 MetadataReaderTypeFilter#match进行判断。

条件的判断主要使用 excludeFiltersincludeFilters 两个字段决定。那两个字段从何处生成?

原来在ComponentScanBeanDefinitionParser中调用 ClassPathBeanDefinitionScanner构造方法时,默认传入 useDefaultFilters=true

registerDefaultFilters 注册默认的过滤器,生成 excludeFiltersincludeFilters初始值。

默认情况下,excludeFilters 将会是个空集,而 includeFilters 集合中增加一个包含@Component 类型信息的 AnnotationTypeFilter 实例,以及另外两个包含 Java EE 注解AnnotationTypeFilter 实例。

跳到 AnnotationTypeFilter#match 方法中。AnnotationTypeFilter 类图如下。

AnnotationTypeFilter#match 方法在抽象类 AbstractTypeHierarchyTraversingFilter中实现。

match 方法首先调用了 matchSelf,而该方法最终由 AnnotationTypeFilter 重写。

可以看到这里最终使用 AnnotationMetadata 方法判断是否存在指定注解。

源码分析就到此为止,下篇文章将会深入 AnnotationMetadata,查看其实如何获取元数据的。

帮助文档

Spring Annotation Programming Model
beans-stereotype-annotations
『Spring Boot 编程思想』

spring controller 增加header字段forward_Spring 注解编程之模式注解相关推荐

  1. 设计模式——Spring注解编程模型

    文章目录 1. 引言 2. Spring注解编程模型 2.1 元注解(Meta-Annotations) 2.2 Spring模式注解(Stereotype Annotations) 2.3 Spri ...

  2. Spring基础专题——第十一章(高级注解编程完结)

    前言:去年到现在一直没有很好的时间完成这个spring基础+源码的博客目标,去年一年比较懒吧,所以今年我希望我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从 ...

  3. Spring基础专题——第九章(基础注解编程——上)

    目标,去年一年比较懒吧,所以今年我希望我的知识可以分享给正在奋斗中的互联网开发人员,以及未来想往架构师上走的道友们我们一起进步,从一个互联网职场小白到一个沪漂湿人,一路让我知道分享是一件多么重要的事情 ...

  4. Spring注解编程基石(一)

    目录 Java注解 Java原生注解 元注解 Stereotype 注解 组合注解 组合注解实现的基础 @AliasFor 隐式别名 @AliasFor 和 @Inherited 区别 注解解析工具 ...

  5. Spring注解编程基石(二)

    目录 辅助类 AttributeMethods AnnotationFilter RepeatableContainers MergedAnnotation接口 AnnotationsProcesso ...

  6. Spring注解编程基石(三)

    目录 AnnotationUtils 源码分析 方法列表 方法源码 AnnotatedElementUtils 源码分析 Spring注解编程基石(一) Spring注解编程基石(二) Spring注 ...

  7. Spring注解编程基石(四)

    目录 AnnotationsScanner 扫描方法 扫描source为Class方法 扫描source为Method方法 辅助方法 MergedAnnotationSelector MergedAn ...

  8. 利用Spring扩展点模拟MyBatis的注解编程「知识点多多」「扩展点实战系列」- 第448篇

    历史文章(文章累计440+) <国内最全的Spring Boot系列之一> <国内最全的Spring Boot系列之二> <国内最全的Spring Boot系列之三> ...

  9. Spring基础篇:高级注解编程

    文章内容来自于B站孙哥说Spring 第一章:@Configuration 一:配置Bean替换XML细节 二:应用配置Bean工厂对象 三:配置Bean细节分析 1:整合Logback 三:@Com ...

最新文章

  1. ubuntu安装rar win解压缩工具
  2. python学习之turtle库基本操作
  3. php用于防SQL注入的几个函数
  4. ArcGIS 的 http://localhost:8399/arcgis/rest/services 无法打开,显示404 的解决办法
  5. 新晋“网红”Cat1 是什么
  6. 有哪些关于iPhone使用的小技巧?
  7. 20个问题:平凡的天才人格特质
  8. yii CComponent组件 实例说明1
  9. Illustrator 教程,如何在 Illustrator 中重新塑造文本?
  10. 一文弄懂数据挖掘的十大算法,数据挖掘算法原理讲解
  11. EasyRecovery注册码哪里有?
  12. 硬件安全模块- HSM
  13. layabox 打印_Layabox 集成指南
  14. centons7安装k8s集群
  15. 秋招经验总结(私企,外企,国企)
  16. c语言实验作业在dev蜗居的思路,C语言程序设计实验(共5篇)
  17. ADFS 概念与基本开发介绍 (1)
  18. zuk z2刷机android p,zuk z2p 解锁详细步骤
  19. Redis Desktop Manager连接失败/超时?
  20. Mongodb 索引 对查询结果的排序

热门文章

  1. php的mbstring模块安装折腾记录
  2. 【codevs1036】商务旅行,LCA练习
  3. C ++ 类 | 类的创建和使用_1
  4. jsp测试连接mysql_JSP 连接MySQL配置与测试
  5. 自走棋电脑版_手游版《自走棋》上线试玩
  6. php滚动图代码,JS上下、左右滚动代码(支持图片滚动)
  7. Android中VectorDrawable与SVG
  8. CentOS 7 SSH相关使用问题及其解决办法
  9. python十大实例_Python练习实例100例(从简入难)96-100
  10. python 运行时 变量_python运行过程,变量,符号