Spring注解编程模式


概况

多年来,Spring Framework不断发展对注解、元注解和组合注解的支持。 本文档旨在帮助开发人员(Spring的最终用户以及Spring Framework和Spring组合项目的开发人员)开发和使用Spring注解。


本文档的目标

本文档的主要目标包括以下内容的解释:

  • 如何使用Spring注解。
  • 如何开发用于Spring的注解。
  • Spring如何找到注解(即Spring的注解搜索算法如何工作)。

不属于本文档目标内容

本文档的目的不是解释Spring Framework中特定注解的语义或配置选项。有关特定注解的详细信息,建议开发人员查阅对应的Javadoc或参考手册的相应部分。


术语


元注解

元注解是在另一个注解上声明的注解。如果一个注解使用其他注解进行注解,因此,这个注解被元注解。例如,声明要记录的任何注解都是使用java.lang.annotation包中的@Documented进行元注解的。


构造型注解

构造型注解是一种注解,用于声明组件在应用程序中扮演的角色。 例如,Spring Framework中的@Repository注解是任何满足存储库角色或构造型(也称为数据访问对象或DAO)的类的标记。

@Component是任何Spring管理组件的通用构造型。使用@Component注解的任何组件都是作为等待被扫描的组件。类似地,任何使用@Component进行元注解的注解,那么其注解的组件也是作为将要被扫描的组件。 例如,@Service使用@Component进行元注解。

Core Spring提供了几种开箱即用的构造型注解,包括但不限于:@Component@Service@Repository@ Controller@RestController@Configuration@Repository@Service等是@Component的特化。


组合注解

组合注解是使用一个或多个注解进行元注解的注解,其目的是将与这些元注解相关联的行为组合到单个自定义注解中。 例如,使用Spring的@Transactional@Service注解进行元注解的名为@TransactionalService的注解是一个组合注解,它结合了@Transactional@Service的语义。@TransactionalService在技术上也是一个自定义构造型注解。


注解存在

直接存在,间接存在和存在的术语与Java 8中java.lang.reflect.AnnotatedElement的类级别Javadoc中定义的含义相同。

在Spring中,如果注解被声明为元素上存在的其他注解上的元注解,则注解被认为是元素上的元存在。 例如,给定前面提到的@TransactionalService,我们会说@Transactional在任何直接用@TransactionalService注解的类上都是元存在的。


属性别名与覆盖

一个属性别名是从一个注解属性到另一个注解属性的别名。 一组别名中的属性可以互换使用,并视为等效。 属性别名可以按如下分类:

  • 显式别名:如果一个注解中的两个属性通过@AliasFor声明为彼此的别名,则它们是显式别名。
  • 隐式别名:如果一个注解中的两个或多个属性通过@AliasFor声明为元注解中同一属性的显式覆盖,则它们是隐式别名。
  • 传递隐式别名:在一个注解中给出两个或多个属性,通过@AliasFor声明为元注解中属性的显式覆盖,如果属性有效地覆盖符合传递规律的元注解中的相同属性,则它们是传递性的 隐含别名。

一个属性覆盖是一种注解属性,它覆盖(或隐藏)元注解中的注记属性。 属性覆盖可以按如下分类:

  • 隐式覆盖:给定注解@One中的属性A和注解@Two中的属性A,如果@One使用@Two进行元注解,则注解@One中的属性A是注解@Two中属性A的隐式覆盖,仅基于命名约定(即两个属性都命名为A)。
  • 显式覆盖:如果属性A在@AliasFor的元注解中被声明为属性B的别名,则A是B的显式覆盖。
  • 传递显式覆盖:如果注解@One中的属性A是注解@Two中属性B的显式覆盖,而属性B是注解@Three 中的属性C的显式样覆盖,则A是遵循传递定律的C的传递显式覆盖。

例子

Spring Framework和Spring组合项目中的许多注解都使用@AliasFor注解来声明属性别名和属性覆盖。 常见的例子包括来自Spring MVC的@ RequestMapping@GetMapping和@PostMapping,以及来自Spring Boot的@SpringBootApplication@SpringBootTest等注解。


使用@AliasFor声明属性别名

Spring Framework 4.2引入了最好的支持,用于声明和查找注解属性的别名。 @AliasFor注解可用于在单个注解中声明一对别名属性,或者将自定义组合注解中的一个属性的别名声明为元注解中的属性。

例如,spring-test模块的@ContextConfiguration声明如下。

public @interface ContextConfiguration {

    @AliasFor("locations")
String[] value() default {}; @AliasFor("value")
String[] locations() default {}; // ...
}

locations属性被声明为value属性的别名,反之亦然。 因此,@ContextConfiguration的以下声明是等效的。

@ContextConfiguration("/test-config.xml")
public class MyTests { /* ... */ } @ContextConfiguration(value = "/test-config.xml")
public class MyTests { /* ... */ } @ContextConfiguration(locations = "/test-config.xml")
public class MyTests { /* ... */ }

相似地,覆盖元注解中的属性的组合注解可以使用@AliasFor对注解层次结构中的哪些属性进行细粒度控制。 实际上,甚至可以为元注解的value属性声明别名。

例如,可以使用自定义属性覆盖开发组合注解,如下所示:

@ContextConfiguration
public @interface MyTestConfig { @AliasFor(annotation = ContextConfiguration.class, attribute = "value")
String[] xmlFiles(); // ...
}

上面的示例演示了开发人员如何实现自己的自定义组合注解; 然而,以下解释Spring本身在许多核心Spring注解中使用了这个特性:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping { /**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class)
String name() default ""; /**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {}; /**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {}; // ...
}

Spring Composed和Spring Polyglot

Spring Composed项目是一个用于Spring Framework 4.2.1及更高版本的组合注解的集合。 在那里你会发现@Get@Post@Put@Delete等注解,它们是@GetMapping@PostMapping@PutMapping@DeleteMapping注解的灵感来源,这些注解现在是Spring MVC和Spring WebFlux的一部分。

请随意参考spring-composed项目以获得更多示例和灵感,了解如何实现自己的自定义组合注解,以及进一步展示@AliasFor功能带来的极客幽默和娱乐,请查看Spring Polyglot


常见问题解答

1)@AliasFor可以与@Component@Qualifier的值属性一起使用吗?

最简洁的答案是不。

@AliasFor不会影响@Qualifier和构造型注解中的值属性(例如@Component@Repository@Controller和任何自定义构造型注解)。 原因是这些价值属性的特殊处理在@AliasFor发明之前的几年就已经存在。 因此,由于向后兼容性问题,根本不可能将@AliasFor与这些值属性一起使用。


尚未涵盖的主题

  • 记录关于类、接口、方法、字段、参数和注解的注解和元注解的一般搜索算法。

    • 如果注解在本地和元注解中都存在于元素中会发生什么?
    • @Inherited在注解(包括自定义组合注解)上的存在如何影响搜索算法?
  • 对通过@AliasFor配置的注解属性别名的文档支持。

    • 如果在一个注解实例(具有相同值或具有不同值)中声明属性及其别名,会发生什么?

      • 通常会抛出AnnotationConfigurationException。
  • 对组合注解的文档支持

  • 对在组合注解中元注解属性覆盖的文档支持

    • 记录查找属性时使用的算法,具体说明:

      • 基于命名约定的隐式映射(即,组合注释声明具有与重写的元注解中声明的完全相同的名称和类型的属性)
      • 使用@AliasFor显式映射
      • 如果属性及其中一个别名在注解层次结构中的某处声明,会发生什么? 哪一个优先?
      • 一般,如何解决涉及注解属性的冲突?

英文原版

翻译:Evan Leung

[Spring Annotation Programming Model]https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model

跟Evan学Sprign编程思想 | Spring注解编程模式【译】的更多相关文章

  1. 小马哥讲Spring栈核心编程思想 Spring IoC+Bean+Framework

    小马哥出手的Spring栈核心编程思想课程,可以说是非常专业和权威的Spring课程.课程主要的方向与核心是Spring Framework总览,带领同学们重新认识重新认识IoC,Spring IoC ...

  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 注解编程之模式注解

    Spring 框架中有很多可用的注解,其中有一类注解称模式注解(Stereotype Annotations),包括 @Component, @Service,@Controller,@Reposit ...

  6. 编程思想—面向切面编程(AOP)

    谈到面向切面的编程,我们很容易关联到面向对象编程(OOP).个人对这两种编程方式的解释为:两种编程思想只是站在编程的角度问题. OOP注重的是对象,怎么对对象行为和方法的抽象.如何封装一个具有完整属性 ...

  7. java编程思想-java注解

    注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据. 一.定义注解 注解的定义看起来很像接口的定义.事实上,与其他任何Java接口一样, ...

  8. Java编程思想-基于注解的单元测试

    Junit的测试方法命名不一定以test开头 上面介绍的atunit已经很老了,现在junit测试框架已经基本注解了

  9. Spring 注解编程之 AnnotationMetadata

    在上篇文章 Spring 注解编程之模式注解 中我们讲到 Spring 模式注解底层原理,依靠 AnnotationMetadata 接口判断是否存在指定元注解. 这篇文章我们主要深入 Annotat ...

随机推荐

  1. go微服务框架kratos学习笔记五(kratos 配置中心 paladin config sdk [断剑重铸之日,骑士归来之时])

    目录 go微服务框架kratos学习笔记五(kratos 配置中心 paladin config sdk [断剑重铸之日,骑士归来之时]) 静态配置 flag注入 在线热加载配置 远程配置中心 go微 ...

  2. node.js UDP NAT 穿透实现

    源码:https://github.com/zhongchengyi/node-udp-trunnel-demo 1.原理 A登录Server, NAT A 分配端口11000,Server得到A的地 ...

  3. 机器学习回顾篇(12):集成学习之Bagging与随机森林

    .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px so ...

  4. Python综合应用:教你用字符打印一张怀旧风格的照片

    1. 前言第一次在学校机房里见到计算机,还是上古时期.计算机型号大概是LASER-310吧,有点记不清了.那会儿,显示器还是单色的,只能显示文本,每行最多显示80个字符.想看图片,印象中只能用针式打印 ...

  5. 【题解】BZOJ4883: [Lydsy1705月赛]棋盘上的守卫(最小生成基环森林)

    [题解]BZOJ4883: [Lydsy1705月赛]棋盘上的守卫(最小生成基环森林) 神题 我的想法是,每行每列都要有匹配且一个点只能匹配一个,于是就把格点和每行每列建点出来做一个最小生成树,但是不 ...

  6. 洛谷$P3756\ [CQOI2017]$老$C$的方块 网络流

    正解:网络流 解题报告: 传送门$QwQ$ 看到不能出现给定的讨厌的图形,简单来说就,特殊边两侧的方格不能同时再连方格. 所以如果出现,就相当于是四种方案?就分别炸四个格子. 然后冷静分析一波之后发现 ...

  7. $POJ$3252 $Round\ Numbers$ 数位$dp$

    正解:数位$dp$ 解题报告: 传送门$w$ 沉迷写博客,,,不想做题,,,$QAQ$口胡一时爽一直口胡一直爽$QAQ$ 先港下题目大意嗷$QwQ$大概就说,给定区间$[l,r]$,求区间内满足二进制 ...

  8. Spring中常见的设计模式——代理模式

    一.代理模式的应用场景 生活中的中介,黄牛,等一系列帮助甲方做事的行为,都是代理模式的体现.代理模式(Proxy Pattern)是指为题对象提供一种代理,以控制对这个对象的访问.代理对象在客户端和目 ...

  9. Ceph 文件系统 CephFS 的实战配置,等你来学习 -- <4>

    Ceph 文件系统 CephFS 的介绍与配置 CephFs介绍 Ceph File System (CephFS) 是与 POSIX 标准兼容的文件系统, 能够提供对 Ceph 存储集群上的文件访问 ...

  10. schedule of 2016-10-17~2016-10-23(Monday~Sunday)——1st semester of 2nd Grade

    most important things to do 1.joint phd preparations 2.journal paper to write 3.solid fundamental kn ...