https://www.jianshu.com/p/4f65fae2510b

前言

@Repeatable是java8为了解决同一个注解不能重复在同一类/方法/属性上使用的问题。

应用场景

举一个比较贴近开发的例子,在spring/springboot我们引入资源文件可以使用注解@PropertySource

@PropertySource("classpath:sso.properties")
public class Application {
}

那要引入多个资源文件怎么办,没事,我把PropertySource中的value设置成String[]数组就行了

public @interface PropertySource {...String[] value();
}

那么就能这么用

@PropertySource({"classpath:sso.properties","classpath:dubbo.properties","classpath:systemInfo.properties"})
public class Application {
}

就spring引入配置文件来讲,肯定是没事问题的。但是如果注解中2个值存在依赖关系,那么这样就不行了。比如下面这个

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
//@Repeatable(Validates.class)
public @interface Validate {/*** 业务类型* @return*/String bizCode();/*** 订单类型* @return*/int orderType();}

我玩策略模式的时候喜欢用注解和spring结合做自动策略路由

上面的@validate注解,bizcode和orderType是一对一的关系,我希望可以添加如下的注解

@Validate(bizCode = "fruit",orderType = 1)
@Validate(bizCode = "fruit",orderType = 2)
@Validate(bizCode = "vegetable",orderType = 2)
public class BizLogic2 {
}

很抱歉在java8之前,这种方式不行,不过你可以这么做,新建一个如下的注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Validates {Validate[] value();}

注意这个聚合注解默认约束value来存储子注解

然后对应代码修改如下

@Validates(value = {@Validate(bizCode = "fruit",orderType = 1)@Validate(bizCode = "fruit",orderType = 2)@Validate(bizCode = "vegetable",orderType = 2)
})
public class BizLogic2 {
}

在java8的@Repeatable出来之后,我们在不改动@Validates的情况下,对@Validate进行修改,增加@Repeatable(Validates.class)

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Repeatable(Validates.class)
public @interface Validate {/*** 业务类型* @return*/String bizCode();/*** 订单类型* @return*/int orderType();}

那么就可以在类上使用多个@Validate注解了。

回过头来看下@PropertySource和@PropertySources也是如此

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource /*** Container annotation that aggregates several {@link PropertySource} annotations.** <p>Can be used natively, declaring several nested {@link PropertySource} annotations.* Can also be used in conjunction with Java 8's support for <em>repeatable annotations</em>,* where {@link PropertySource} can simply be declared several times on the same* {@linkplain ElementType#TYPE type}, implicitly generating this container annotation.** @author Phillip Webb* @since 4.0* @see PropertySource*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PropertySources

从上面的注释中可以看到,spring在4.0支持了java8这个特性

原理

那么@Repeatable的原理是啥?

语法糖而已!

我们反编译下面代码

/*@Validates(value = {*/@Validate(bizCode = "fruit",orderType = 1)@Validate(bizCode = "fruit",orderType = 2)@Validate(bizCode = "vegetable",orderType = 2)
/*})*/
public class BizLogic2 {
}

发现反编译变成了

语法糖无疑了。

问题来了

那么再反编译下面代码试试

/*@Validates(value = {*/@Validate(bizCode = "fruit",orderType = 1)// @Validate(bizCode = "fruit",orderType = 2)//@Validate(bizCode = "vegetable",orderType = 2)
/*})*/
public class BizLogic2 {
}

生成

那这样就存在问题了,我以为加了@Repeatable之后@Validate都会生成被语法糖@Validates包裹。没想到它居然这么智能,只有一个@Validate注解的时候居然不转换。

所以使用多个@Validate的时候就会留坑,你需要兼容1个或多个的场景。

推荐方式

直接使用@Validates读取注解代码如下

Validates validates = AnnotationUtils.getAnnotation(BizLogic2.class,Validates.class);Arrays.stream(validates.value()).forEach(a->{System.out.println(a.bizCode());});

带兼容的逻辑如下

Validate validate = AnnotationUtils.getAnnotation(BizLogic.class,Validate.class);if(Objects.nonNull(validate)){System.out.println(validate.bizCode());}Validates validates = AnnotationUtils.getAnnotation(BizLogic2.class,Validates.class);Arrays.stream(validates.value()).forEach(a->{System.out.println(a.bizCode());});

如果你是自己写业务的,我觉得第一种方式更加方便。
但是如果你是开发中间件的,那么必须兼容,你永远不知道你的傻逼用户会干吗,哈哈。

还有一点需要注意,我的@Validate是被@Component元注解,当多个@Validate语法糖转换成@Validates之后,由于@Validates上没@Component,导致我的bean加载不到spring容器中去

java8注解@Repeatable使用技巧相关推荐

  1. java 元注解 @Repeatable

    目录 一 笔记 二 自定义注解容器Persons 三 自定义的注解AnnotationTest08_Person ,即可重复使用的注解 四 通过反射机制获取重复注解的信息 一 笔记 元注解 @Repe ...

  2. Java注解 @Repeatable

    ** Repeatable使用场景: ** 当我们需要重复使用某个注解时,希望利用相同的注解来表现所有的形式时,我们可以借助@Repeatable注解. ** 实例 ** 在生活中一个人往往是具有多种 ...

  3. 自定义重复注解 @Repeatable 使用方式

    注解基本概要: @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface FieldMap { ...

  4. java8 注解增强_Java8新增的重复注解功能示例

    本文实例讲述了Java8新增的重复注解功能.分享给大家供大家参考,具体如下: 一 点睛 在Java 8以前,同一个程序元素前最多只能使用一个相同类型的Annotation:如果需要在同一个元素前使用多 ...

  5. Java注解——Repeatable

    Repeatable使用场景: 在需要对同一种注解多次使用时,往往需要借助@Repeatable. 实例: 在生活中一个人往往是具有多种身份,如果我把每种身份当成一种注解该如何使用??? 先声明一个P ...

  6. JAVA注解 | 可重复元注解@Repeatable

    目录 使用 @Repeatable 使用反射获取注解 约束 @Repeatable 是 JDK1.8 增加的元注解,用于声明当前注解是可重复的.如果有没有声明 @Repeatable,在同一个地方使用 ...

  7. springboot注解@Repeatable

    @Repeatable 对同一种注解多次使用就会使用到@Repeatable @Documented @Retention(RetentionPolicy.RUNTIME) @Target(Eleme ...

  8. java8函数式编程 视频_快速掌握Java8 Stream函数式编程技巧

    函数式编程优势"函数第一位",即函数可以出现在任何地方. 可以把函数作为参数传递给另一个函数,还可以将函数作为返回值. 让代码的逻辑更清晰更优雅. 减少了可变量(Immutable ...

  9. java8 注解: @FunctionalInterface (函数式接口)

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. Java8提倡函数式编程,因而新增了一个函数式接口.函数式接口保证了函数式编程,同时也保证了能够兼容 ...

最新文章

  1. GPT-2仅是“反刍”知识,真正理解语言还要改弦更张
  2. 使用json-lib实现json to javabean
  3. Oracle 总复习
  4. XDP/eBPF — BPF
  5. Javassist 使用指南(一)
  6. C语言malloc动态分配内存分配失败怎么办?exit(OVERFLOW);(include <cstdlib>)
  7. Python 各种运行错误(如:SyntaxError :invalid syntax)
  8. 计算机网络怎么查看连接打印机驱动,涨姿势:手把手教你如何连接网络打印机...
  9. python减法怎么表示_python运算符号之一的减法怎么用,你真的学会用python的使用方法了嘛...
  10. EditText: 自定义EditText 触摸时无法获取焦点
  11. Android 中点击某个按钮实现 返回键 的功能
  12. 遍历一个数据去掉最后一个元素的样式
  13. String类得常用方法
  14. 项目中cxf和weblogic整合时报错的问题
  15. 二十一、 Memento 备忘录(行为型模式)
  16. Flash之swf文件的加密与破解
  17. 大国崛起:数据库领域的中国力量
  18. matlab如何把正弦转化为余弦公式,余弦和正切的换算关系(正弦余弦正切转换公式大全)...
  19. UVALive - 4487 HDU3234 UVA12232 【带权并查集】 非常好的一道题!!!
  20. Python翻译库 pygtrans 谷歌翻译

热门文章

  1. 《禅门锻炼说》十三篇自序
  2. office2010 启动man_OFFICE2010启动慢解决方案
  3. vant Ui 网址
  4. python:ai第五课:决策树的python实现调试,tree存储恢复,tree图绘制
  5. 工业互联网让“隔行”不再“如隔山”
  6. 自定义Dialog(QQ头像选择弹出的对话框)
  7. matlab 中matgray函数
  8. “内聚性”和“耦合性”
  9. 1052 Linked List Sorting (25 分)
  10. wordpress自动配图插件