注解@Repeatable详解

@Repeatable注解是JDK8加入的一个新特性。

本文算是对一个旧知识点的回顾和剖析。

01

未使用@Repeatable之前实现多个注解重复使用

在1.8之前,如果想多次使用一个注解进行描述,是如何完成的呢?举个例子,使用一个ReviewRecord注解来描述相关类、方法的Review信息。

  • 定义注解ReviewRecord和ReviewRecords
package com.wangmengjun.tutorial.annotation;

public @interface ReviewRecord {

  String name();
  String date();
  String comment() default "";;
}

ReviewRecords注解如下:

package com.wangmengjun.tutorial.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface ReviewRecords {

ton  ReviewRecord[] value();
}
  • 使用注解ReviewRecord和ReviewRecords

在使用的时候,需要先指定@ReviewRecords,然后指定多个ReviewRecord,代码示例如下:

  @ReviewRecords({
    @ReviewRecord(name="Eric", date="2019-12-19", comment="No comment"),
    @ReviewRecord(name="Joan", date="2019-12-29")
  })
  public void method1(String name) {
    System.out.println("Hello, " + name);
  }
  • 获取注解方法

获取某个方法ReviewRecord的注解信息,需要先获取ReviewRecords注解,然后通过ReviewRecords注解的value方法获取ReviewRecord数组。

    ReviewRecords recordsAnno = ReviewRecordExample1.ctolass.getMethod("method1", String.class).getAnnotation(ReviewRecords.class);
    for(ReviewRecord recordAnno : recordsAnno.value()) {
      System.out.println(recordAnno);
    }

输出内容:

@com.wangmengjun.tutorial.annotation.ReviewRecord(comment="No comment", name="Eric", date="2019-12-19")
@com.wangmengjun.tutorial.annotation.ReviewRecord(comment="", name="Joan", date="2019-12-29")

这种旧式写法,可以查看javax.annotation.Resource和javax.annotation.Resources的示例,如:

02

使用@Repeatable后实现多个注解重复使用

修改ReviewResource注解,增加@Repeatable表明其可以重复使用。

package com.wangmengjun.tutorial.annotatiotn;

import java.lang.annotation.Repeatable;

@Repeatable(ReviewRecords.class)
public @interface ReviewRecord {

  String name();
  String date();
  String comment() default "";;
}

使用的时候,不需要指定是ReviewRecords,如:

  @ReviewRecord(name="Eric", date="2019-12-19", comment="No comment")
  @ReviewRecord(name="Joan", date="2019-12-29")
  public void method3(String message) {
    System.out.println(message);
  }

这种方法本质上等同于如下代码:

  @ReviewRecords({
    @ReviewRecord(name="Eric", date="2019-12-19", comment="No comment"),
    @ReviewRecord(name="Joan", date="2019-12-29")
  })
  public void method3(String name) {
    System.out.println("Hello, " + name);
  }

这个我们可以通过javap查看编译后的信息获取:

如:javap -v ReviewRecordExample1.class

  • 获取注解方法

获取注解可以通过getAnnotationsByType来获取即可。

    ReviewRecord[] recordAnnoArr = ReviewRecordExample1.class.getMethod("method3", String.class).getAnnotationsByType(ReviewRecord.class);
    for(ReviewRecord recordAnno : recordAnnoArr) {
      System.out.println(recordAnno);
    }

现在很多地方都使用@Repeatable注解了,如sping-boot-test中的MockBean、MockBeans以及SpyBean和SpyBeans等,如:

03

小结

通过上述的示例,相信大家对@Repeatable注解的使用有了一定的了解。接下来,我们来做一个小结:

  • 使用@Repeatable注解可以让一个注解是否可以重复,意思更加明确
@Repeatable(ReviewRecords.class)
public @interface ReviewRecord {

  String name();
  String date();
  String comment() default "";;
}
  • 使用@Repeatable注解后,其本质是对原先语法的增强

使用@Repeatable注解后,可以支持如下场景:

  @ReviewRecord(name="Eric", date="2019-12-19", comment="No comment")
  @ReviewRecord(name="Joan", date="2019-12-29")
  public void method1(String name) {
    System.out.println("Hello, " + name);
  }

这个其本质就是:

  @ReviewRecords({
    @ReviewRecord(name="Eric", date="2019-12-19", comment="No comment"),
    @ReviewRecord(name="Joan", date="2019-12-29")
  })
  public void method3(String name) {
    System.out.println("Hello, " + name);
  }
  • 使用@Repeatable注解后,一个和多个可以配套使用

可以采用原先的方式:

    @ReviewRecords({
        @ReviewRecord(name="Eric", date="2019-12-19", comment="No comment"),
        @ReviewRecord(name="Joan", date="2019-12-29")
      })
      public void method1(String name) {
        System.out.println("Hello, " + name);
      }
  
  
  @ReviewRecords({@ReviewRecord(name="Eric", date="2019-12-19", comment="No comment")})
  public void method2(String message) {
    System.out.println(message);
  }

可以使用新的方式:

  @ReviewRecord(name="Eric", date="2019-12-19", comment="No comment")
  @ReviewRecord(name="Joan", date="2019-12-29")
  public void method1(String name) {
    System.out.println("Hello, " + name);
  }
  
  //这种方式原来也支持,但是和多个重复注解的配置有配置上不同
  //但是,使用@Repeatable引入后,一个和多个可以匹配上
  @ReviewRecord(name="Eric", date="2019-12-19", comment="No comment")
  public void method2(String message) {
    System.out.println(message);
  }

两种方式,大家都可以使用。本文比较偏向于第二种,你们喜欢哪一个?

posted @ 2024-04-03 16:51  CharyGao  阅读(365)  评论(0编辑  收藏  举报