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

需要配置开启自动扫描。如在 XML 中配置 ` 或使用注解 @ComponentScan。

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

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

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 就被称作为元注解。后面我们就将注解的注解称为元注解。

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 注解编程之模式注解的更多相关文章

  1. 跟Evan学Sprign编程思想 | Spring注解编程模式【译】

    Spring注解编程模式 概况 多年来,Spring Framework不断发展对注解.元注解和组合注解的支持. 本文档旨在帮助开发人员(Spring的最终用户以及Spring Framework和S ...

  2. Spring 注解(一)Spring 注解编程模型

    Spring 注解(一)Spring 注解编程模型 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring 注解系列 ...

  3. Spring 注解编程之注解属性别名与覆盖

    前两篇文章咱聊了深入了解了 Spring 注解编程一些原理,这篇文章我们关注注解属性方法,聊聊 Spring 为注解的带来的功能,属性别名与覆盖. 注解属性方法 在进入了解 Spring 注解属性功能 ...

  4. 理解 Spring 注解编程模型

    理解 Spring 注解编程模型 Spring 中有一个概念叫「元注解」(Meta-Annotation),通过元注解,实现注解的「派生性」,官方的说法是「Annotation Hierarchy」. ...

  5. Spring和SpringMVC的常用注解

    Spring的部分: 使用注解之前要开启自动扫描功能 其中base-package为需要扫描的包(含子包). <context:component-scan base-package=" ...

  6. Spring-构造注入&注解注入&代理模式&AOP

    1.   课程介绍 1.  依赖注入;(掌握) 2.  XML自动注入;(掌握) 3.  全注解配置;(掌握) 4.  代理模式;(掌握) 5.  AOP;(掌握) 依赖注入;(掌握) 2.1.  构 ...

  7. spring事务详解(基于注解和声明的两种实现方式)

    Spring事务( Transaction ) 事务的概念 事务是一些sql语句的集合,作为一个整体执行,一起成功或者一起失败. 使用事务的时机 一个操作需要多天sql语句一起完成才能成功 程序中事务 ...

  8. [Spring]IoC容器之进击的注解

    先啰嗦两句: 第一次在博客园使用markdown编辑,感觉渲染样式差强人意,还是github的样式比较顺眼. 概述 Spring2.5 引入了注解. 于是,一个问题产生了:使用注解方式注入 JavaB ...

  9. SSH(Struts2+Spring+Hibernate)框架搭建流程<注解的方式创建Bean>

    此篇讲的是MyEclipse9工具提供的支持搭建自加包有代码也是相同:用户登录与注册的例子,表字段只有name,password. SSH,xml方式搭建文章链接地址:http://www.cnblo ...

随机推荐

  1. UVALive 6531 Go up the ultras 单调栈+RMQ

    题目链接:点击打开链接 题意: 给定n座山 以下n个数字表示n座山的高度 若这座山u合法,则要满足: 1.若u的左边存在比u高的山,设v是u左边距离u近期的且严格比u高的山,在[v,u]之间至少有一座 ...

  2. win10 开机启动vmware并自动启动虚机

    思路 先实现程序或者命令启动VM并启动虚机,然后再开机启动这个程序. 1.实现一键启动VM和虚机 找了一圈的资料,有两个方法,都测试了,最终比较有效的是下面这个命令 "C:\Program ...

  3. 关于提高UDP发送效率的方法

    UDP的发送效率和什么因素有关呢? 直观觉得,UDP的切包长越大,应该发送效率越高(最长为65536).可是依据实际測试和在网上查到的资料的结果,包长度为1024为发送效率最高. 这样的结果让人感到疑 ...

  4. DDD实战3 领域层的设计

    1.新建一个解决方案文件夹 取名Product 2.在Product解决方案文件夹下面创建一个.net core 类库项目 取名Product.Domain,引用项目DDD.Base项目 3.在类库下 ...

  5. 微信小程序 获取用户信息 encryptData解密 C#版本

    最近学习小程序开发,需要对encryptData解密,获取用户信息,官方源码没有C#版本,网上的资料比较杂,有的使用还有问题,下面贴一下自己亲试可以使用的一个源码 1.code 换取 session_ ...

  6. 【Java】【Flume】Flume-NG阅读源代码AvroSink

    org.apache.flume.sink.AvroSink是用来通过网络来数据传输的.能够将event发送到RPCserver(比方AvroSource),使用AvroSink和AvroSource ...

  7. 开源库(要不要重新制造轮子)—— C/C++、Java、Python

    谷歌近期开源的SLAM方案:Cartographer Boost:准标准的C++库. Eigen3: 准标准的线性代数库. Lua:非常轻量的脚本语言,主要用来做Configuration Ceres ...

  8. [自带避雷针]DropShadowEffect导致内存暴涨

    原文:[自带避雷针]DropShadowEffect导致内存暴涨  [自带避雷针]DropShadowEffect导致内存暴涨 周银辉 从学习WPF开始, 就知道"位图效果"不是什 ...

  9. 【C++】int转string,double转string方法,string转int,string转double方法

    C++的格式比较多比较复杂,转换起来有很多方法,我这里只提供一种,仅供参考. int或double转string 使用字符串流的方式可以比较简单的完成转换 需要添加头文件 #include <s ...

  10. Java 知识笔记 - 类、集合、多线程、IO、JVM(最后一次更新,2019年02月17日)

    目录 Class 内部类.静态内部类.匿名内部类.局部内部类 Collection Java Collection Set Queue Map Collections Arrays System Co ...