Java中的@Repeatable注解使用详解

 更新时间:2024年02月02日 08:58:41   作者:真正的大师学徒的心  
这篇文章主要介绍了Java中的@Repeatable注解使用详解,@Repeatable注解是java8为了解决同一个注解不能重复在同一类/方法/属性上使用的问题,本文提供了解决思路和部分实现代码,需要的朋友可以参考下

@Repeatable

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

@Repeatable是jdk8中新增的注解,使用如Spring中的@ComponentScan注解。

在没有@Repeatable注解的的注解中,在同一个地方使用相同的注解会报错,有了此元注解注解的注解,就可以在同一个地方使用相同的注解。

举例说明

举一个比较贴近开发的例子,在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)
public @interface Validate {
    /**
     * 业务类型
     * @return
     */
    String bizCode();

    /**
     * 订单类型
     * @return
     */
    int orderType();
}

上面的@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();

}

然后对应代码修改如下

@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();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Validates {

    Validate[] value();

}

注意,一旦使用Repeatable注解指定了注解Validates,那么这个聚合注解默认约束value来存储子注解,用其他的名字代替value均会编译报错

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

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

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

@Repeatable 原理

那么@Repeatable的原理是啥? 其实就是语法糖

对于下面的注解

@Repeatable(Persons.class)
public @interface Person {
    String role() default "";
    String name() default "";
}
public @interface Persons {
    Person[] value();
}

我们给下面这个类加上注解,重点关注这个类,打开这个编译后的类(即这个java文件对应的class文件)

@Person(role = "警察",name = "小花")
@Person(role = "小偷",name = "笑话")
public class AnnotationTest {
}

我们得到下面的代码

@Persons({@Person(
    role = "警察",
    name = "小花"
), @Person(
    role = "小偷",
    name = "笑话"
)})
public class AnnotationTest {
    public AnnotationTest() {
    }
}

从这里可以看出的确就是语法糖。

问题来了 我们打开下面这个编译后的类

@Person(role = "警察",name = "小花")
public class AnnotationTest {
}

得到的结果是这样

@Person(
    role = "警察",
    name = "小花"
)
public class AnnotationTest {
    public AnnotationTest() {
    }
}

那这样就存在问题了,我以为加了@Repeatable之后@Validate都会生成被语法糖@Validates包裹。

没想到它居然这么智能,只有一个@Validate注解的时候居然不转换。

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

到此这篇关于Java中的@Repeatable注解使用详解的文章就介绍到这了,更多相关@Repeatable注解使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现可配置换肤的方法示例

    Java实现可配置换肤的方法示例

    本文主要介绍了Java实现可配置换肤的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • Java一致性Hash算法的实现详解

    Java一致性Hash算法的实现详解

    这篇文章主要介绍了Java一致性Hash算法的实现详解,hash的意思是散列,目的将一组输入的数据均匀的分开、打散,往往用来配合路由算法做负载均衡,多用在分布式系统中,需要的朋友可以参考下
    2024-01-01
  • springboot集成JWT之双重token的实现

    springboot集成JWT之双重token的实现

    本文主要介绍了springboot集成JWT之双重token的实现,前端使用accessToken进行登录和验证,后端使用refreshToken定期更新accessToken,具有一定的参考价值,感兴趣的可以了解一下
    2025-03-03
  • Java获取客户端真实IP地址经典写法与Lambda写法对比示例代码

    Java获取客户端真实IP地址经典写法与Lambda写法对比示例代码

    在网络编程中,获取客户端的IP地址和端口地址是非常常见的需求,这篇文章主要介绍了Java获取客户端真实IP地址经典写法与Lambda写法对比的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-05-05
  • 吊打Java面试官之Lambda表达式 Stream API

    吊打Java面试官之Lambda表达式 Stream API

    这篇文章主要介绍了吊打Java之jdk8的新特性包括Lambda表达式、函数式接口、Stream API全面刨析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • 快速解决commons-fileupload组件无法处理自定义head信息的bug

    快速解决commons-fileupload组件无法处理自定义head信息的bug

    问题在于fileupload组件解析完自定义的head节点后,却忘记传递到FileItemStreamImpl中了,稍作修订,即可修正该bug
    2013-08-08
  • springboot配置logback日志管理过程详解

    springboot配置logback日志管理过程详解

    这篇文章主要介绍了springboot配置logback日志管理过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • java求100以内的素数示例分享

    java求100以内的素数示例分享

    素数是指因数只有1和本身的数字,这篇文章主要介绍了java求100以内的素数示例,需要的朋友可以参考下
    2014-03-03
  • 深入学习java枚举的应用

    深入学习java枚举的应用

    本篇是关于java深入提高学习的相关知识,介绍了枚举的应用等方面内容,有兴趣的朋友参考学习下吧。
    2018-01-01
  • Java实现两人五子棋游戏(二) 画出棋盘

    Java实现两人五子棋游戏(二) 画出棋盘

    这篇文章主要为大家详细介绍了Java实现两人五子棋游戏,画出五子棋的棋盘,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03

最新评论