注解@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);
}
两种方式,大家都可以使用。本文比较偏向于第二种,你们喜欢哪一个?