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

注解属性方法

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

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

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

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

其次,注解属性方法可以使用 default设置默认值。如果没有设置默认值,声明注解时必须显式设置属性,否则编译将会出错。

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

Spring 属性方法特性

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

在 WEB 项目中,设置 url 路径,我们可以在方法是这样声明:

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

上面方法本质使用注解 value 属性。当注解声明时只需要设置一个方法时,如果属性方法为 value,不需要使用 key=value 的语法,只需要直接设置属性值即可。

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

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

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

查看 RequestMapping 注解源码,可以发现在 valuepath 属性方法上使用 @AliasFor,并且两个互相指向对方。

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#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声明后互为别名,那么它们是显式别名

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

隐式别名

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

隐式别名如图所示。

上图中,@Onename 属性与 nameAlias 别名与 @Two nameAlias 属性。由于 @One 注解中并未直接使用 @AliasFor,所以与 @One 注解隐式别名。

隐式别名类似于数学的等式。可以将其看做以下推导过程。

@One.name=@Two.nameAlias
@One.nameAlias=@Two.nameAlias
可以推导出
@One.name=@One.nameAlias

传递式隐式别名

如果一个注解中的两个或者更多成员通过@AliasFor声明去覆盖元注解中的不同成员,但是实际上因为覆盖的传递性导致最终覆盖的是元注解中的同一个成员,那么它们就是传递隐式别名。

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

这种类型涉及了多个注解,@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 属性覆盖。

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

显示覆盖

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

传递式显式覆盖

如果注解 @One#name 显示覆盖了 @Two#nameAlias,而 @Two#nameAlias 显示覆盖了 @Three#nameAlias,最后因为传递性,@One#name 实际覆盖了@Three#nameAlias

总结

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

底层原理可以参考 AnnotationUtilsAnnotatedElementUtils

帮助文档

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

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

Spring 注解编程之注解属性别名与覆盖的更多相关文章

  1. spring AOP编程--AspectJ注解方式

    1. AOP 简介 AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, ...

  2. spring AOP 编程--AspectJ注解方式 (4)

    1. AOP 简介 AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, ...

  3. spring 通过编程来获取属性文件

    配置可以读取属性: <beans profile="dev"> <context:property-placeholder ignore-resource-not ...

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

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

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

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

  6. 理解 Spring 注解编程模型

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

  7. Spring 注解编程之模式注解

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

  8. Spring -07 -AOP [面向切面编程] - 使用注解@+ AspectJ 方式实现环绕/前/后等通知 -超简洁 --静态代理/动态代理{JDK/cglib}

    1.spring 不会自动去寻找注解,必须告诉 spring 哪些包下的类中可能有注解;使用注解来取代配置文件.1.1 引入xmlns:context ,指定扫描范围 <context:comp ...

  9. 【Spring注解驱动开发】如何使用@Value注解为bean的属性赋值,我们一起吊打面试官!

    写在前面 在之前的文章中,我们探讨了如何向Spring的IOC容器中注册bean组件,讲解了有关bean组件的生命周期的知识.今天,我们就来一起聊聊@Value注解的用法. 项目工程源码已经提交到Gi ...

随机推荐

  1. 关于JSP

    JSP的本质 JSP本质上就是Servlet, 正常情况下, 它会在第一次被访问的时候被容器转化成Java代码, 然后再从Java代码编译成.class文件, 之后实际就和Servlet没区别了, 也 ...

  2. style文件的指定

    新建资源文件   写资源文件 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/prese ...

  3. GlyphRun 对象和 Glyphs 元素简介

    原文 GlyphRun 对象和 Glyphs 元素简介 GlyphRun 简介 Windows Presentation Foundation (WPF) 提供高级的文本支持包括直接访问的标志符号级标 ...

  4. 零元学Expression Blend 4 - Chapter 9 用实例了解布局容器系列-「Canvas」

    原文:零元学Expression Blend 4 - Chapter 9 用实例了解布局容器系列-「Canvas」 本系列将教大家以实做案例认识Blend 4 的布局容器,此章介绍的布局容器是Blen ...

  5. oracle rac 修改dbid和dbname

    =======================修改数据库dbid====================== 1.查看目前数据库dbid以及dbname [root@rac01 ~]# su - or ...

  6. 龙芯GO!龙芯平台上构建Go语言环境指南

    龙芯软件生态系列——龙芯GO!龙芯平台上构建Go语言环境指南2016-07-05 龙芯中科1初识Go语言Go语言是Google公司于2009年正式推出的一款开源的编程语言,是由Robert Gries ...

  7. winform窗体绑定监控键盘事件

    直接注册是触发不了的, 例如: 总是不能触发. 需要在窗体设置一直属性: 大概意思是在无论窗体的那个子元素获得焦点,都将触发监控键盘的事件.

  8. Qt编程规范

    一.概述 良好的编程规范可以大幅提高一个程序的可读性.可理解性和可维护性. 本规范参考Effective C++中文版.Google C++编码规范及Qt编码风格. 二.头文件 1)      #de ...

  9. 使用 docker 搭建 nginx+php-fpm 环境 (两个独立镜像)

    :first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdow ...

  10. 自己动手写jQuery插件---Tip(提示框)

    对jQuery相信很多同学和我一样平时都是拿来主义,没办法,要怪只能怪jQuery太火了,各种插件基本能满足平时的要求.但是这毕竟不是长久之道,古人云:“授之以鱼,不如授之以渔”. 为了方便之前没有接 ...