java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > @Repeatable注解使用

Java中的@Repeatable注解使用详解

作者:真正的大师学徒的心

这篇文章主要介绍了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注解使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文