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

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

注解属性方法

在进入了解 Spring 注解属性功能以前,咱们先看一个正常 Java 注解。git

annotation.png

在注解中,属性方法与其余类/接口方法写法相似,可是存在一些区别。github

注解属性方法的返回类型仅限为八种基本类型(包装类不支持),字符串,class,enum,Annotation以及前面类型的数组。spring

复习一下,java 八种基本类型分别为,byte(字节型)、short(短整型)、int(整型)、long(长整型)、float(单精度浮点型)、double(双精度浮点型)、boolean(布尔型)、char(字符型)。编程

其次,注解属性方法可使用 default设置默认值。若是没有设置默认值,声明注解时必须显式设置属性,不然编译将会出错。数组

另外 Java 注解没法继承类,也没法实现接口。app

Spring 属性方法特性

在 Spring 中,有一些注解,使用不一样属性方法,却能到达相同结果。典型的如 RequestMappingide

在 WEB 项目中,设置 url 路径,咱们能够在方法是这样声明:url

@RequestMapping("hello")
    public String helloAnnotation() {
    。。。。
    }

上面方法本质使用注解 value 属性。当注解声明时只须要设置一个方法时,若是属性方法为 value,不须要使用 key=value 的语法,只须要直接设置属性值便可。设计

另外也可使用 path 属性方法设置。

@RequestMapping(path = "hello")
    public String helloAnnotation() {
    。。。。
    }

两种方式,最后运行效果一致。

查看 RequestMapping 注解源码,能够发如今 valuepath 属性方法上使用 @AliasFor,而且两个互相指向对方。

RequestMapping.png

Spring 4.2 加入 @AliasFor 注解,并使用 @AliasFor 从新更新 RequestMapping等注解,为它们内部带来了别名的功能。

@AliasFor 使用方式

在 Spring 中,@AliasFor 能够在同一注解中使用,使用方法如 RequestMapping 注解。

这种方式,带来含义明确属性方法。如 RequestMappingpath 属性方法,这个属性方法含义就比较明确,不一样的人理解不会有误差。而 value 属性含义就不是很明确,不能一会儿就将它真正含义产生联系。

平常开发中,咱们也要避免 i,a,b 这些无心义的命名,尽可能使用含义明确的命名。这样利用维护代码的人理解。

第二点,同一注解属性方法相互别名,这样就兼容以前版本用法。

RequestMapping 注解若是仅新增 path 属性,而后根据其解析 url 路径,这样就会致使升级 Spring 版本过程,运行错误的。

一个好软件版本须要时向前兼容,如 JDK 8 兼容 JDK 6同样。

另外 @AliasFor 注解还能够做用与不一样注解以前,典型的如 SpringBootApplication注解。

SpringBootApplication.png

SpringBootApplication#scanBasePackages 别名与 ComponentScan#basePackages。设置前者间接为后者赋值。

Spring Boot 就是使用 @Aliasfor 与组合注解功能,使用 SpringBootApplication一个注解代替 ConfigurationEnableAutoConfigurationComponentScan

Spring 注解属性覆盖与别名

使用 @AliasFor 注解,能够作到别名的功能。

在 Spring 中别名能够分为如下几类:

  1. 显式别名(xplicit Aliases
  2. 隐式别名(Implicit Aliases
  3. 传递隐式别名(Transitive Implicit Aliases

以上三类都须要知足如下条件:

  1. 属性类型相同
  2. 属性方法必须存在默认值
  3. 属性默认值必须相同

不然运行过程当中将会出错。

显式别名

若是一个注解中的两个成员经过 @AliasFor声明后互为别名,那么它们是显式别名

显示别名的关系如图所示。

image.png

隐式别名

若是一个注解中的两个或者更多成员经过@AliasFor声明去覆盖同一个元注解的成员值,它们就是隐式别名

隐式别名如图所示。

image.png

上图中,@Onename 属性与 nameAlias 别名与 @Two nameAlias 属性。因为 @One 注解中并未直接使用 @AliasFor,因此与 @One 注解隐式别名。

隐式别名相似于数学的等式。能够将其看作如下推导过程。

@One.name=@Two.nameAlias
@One.nameAlias=@Two.nameAlias
能够推导出
@One.name=@One.nameAlias

传递式隐式别名

若是一个注解中的两个或者更多成员经过@AliasFor声明去覆盖元注解中的不一样成员,可是实际上由于覆盖的传递性致使最终覆盖的是元注解中的同一个成员,那么它们就是传递隐式别名。

传递式隐式别名如图所示。

image.png

这种类型涉及了多个注解,@One#name别名了 @Two#nameAlias属性,而后在 @One#nameAlias 属性又别名了 @Three#nameAliasThree 属性。而后因为 @Two#nameAlias又别名了 @Three#nameAliasThree 属性,这就致使 @One#name@One#nameAlias 间接才生了关系。这种依靠传递性才生别名关系,称为 传递式隐式别名。

隐式别名相似于数学的等式。你们也能够将其用上面等式推导。

属性覆盖

属性覆盖指的是注解的一个成员覆盖另外一个成员,最后二者成员属性值一致。

属性覆盖能够分为三类:

  1. 隐式覆盖(Implicit Overrides
  2. 显示覆盖(Explicit Overrides
  3. 传递式显式覆盖(Transitive Explicit Overrides

隐式覆盖

当一个注解 @One 被元注解 @Two 标注,两个注解存在一样的属性方法 name@Two#name 将会被 @One#name 属性覆盖。

image.png

两个看似不来自不一样注解的成员 name 指向了同一个成员 name。

显示覆盖

显示覆盖就比较简单了,使用 @AliasFor 注解以后,就成为显示覆盖。

image.png

传递式显式覆盖

若是注解 @One#name 显示覆盖了 @Two#nameAlias,而 @Two#nameAlias 显示覆盖了 @Three#nameAlias,最后由于传递性,@One#name 实际覆盖了@Three#nameAlias

image.png

总结

Spring 4.2 新增 @AliasFor注解,带来一些特性。可是要注意的是仅仅存在 @AliasFor 不会执行任何语义别名。

底层原理能够参考 AnnotationUtilsAnnotatedElementUtils

帮助文档

  1. Attribute Aliases and Overrides
  2. 注解编程模型~~~~

其余平台.png

另外欢迎加入 Java 极客技术知识星球,获取最新 Java 技术。

稿定设计导出20190713162903.png

相关文章
相关标签/搜索