Repeating Annotations

在一些场景中你想要在声明或者类型使用上添加一些相关的注解。Java SE 8 release中提供了repeating annotations实现这个功能。

例如,你想使用定时服务编写代码使得在指定时间或者是按特定计划运行一个函数,类似于UNIX中的cron服务。现在你想设置一个定时器去运行函数doPeriodicCleanup,该定时器在每个月的最后一天和每个星期五晚上11点整启动。为了实现定时器,创建一个名为@Schedule的注解,并在doPeriodicCleanup函数上使用两次。第一次我们指定每个月的最后一天,第二次我们指定星期五晚上11点整,具体代码如下所示:

@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")
public void doPeriodicCleanup() { ... }

这个例子在函数上应用注解。你可以使用标准注解的所有地方重复注解。例如,你有一个处理未授权访异常的类,。你在类上为manager和其他admin添加一个@Alert注解:

@Alert(role="Manager")
@Alert(role="Administrator")
public class UnauthorizedAccessException extends SecurityException { ... }

由于兼容的原因,重复注解被保存由Java编译器自动生成的container annotation中。为了让编译器实现上述功能,在你代码中需要两个声明。

Step 1: Declare a Repeatable Annotation Type

注解类型必须被@Repeatable元注解标记,下面这个例子定义了一个名为@Schedule的可重复注解:

import java.lang.annotation.Repeatable;

@Repeatable(Schedules.class)
public @interface Schedule {
  String dayOfMonth() default "first";
  String dayOfWeek() default "Mon";
  int hour() default 12;
}

@Repeatable元注解括号里面的值,就是Java编译器用来生成并保存重复注解的container annotation(容器注解)的类型。这个例子中,容器注解的类型是Schedules,也就是说重复的@Schedule注解保存在一个@Schedules注解中。

将相同的未声明可重复的注解应用在同一个声明中会导致编译时报错。

Step 2: Declare the Containing Annotation Type

容器注解类型必须包含一个数组类型的value元素。数组中元素的类型必须是可重复注解类型。名为Schedules的容器注解声明如下:

public @interface Schedules {
    Schedule[] value();
}

Retrieving Annotations

Reflection API提供了一些函数用来获取注解。有些函数返回单个注解,比如 AnnotatedElement.getAnnotation(Class),如果存在所请求类型的一个注释,它们仅返回单个注释,如果存在一个以上的注解,你可以先通过使用它们的容器注解来获取它们。通过这样,确保遗产代码能正常运行。Java SE 8中的其他函数可以扫描容器注解使得一次放回多个注解,比如AnnotatedElement.getAnnotationsByType(Class)。阅读AnnotatedElement的规范获取跟多信息。

Design Considerations

当设计一个注解类型时,你必须考虑该类型的注解cardinality(基数)。现在可以不使用注解或者使用一次,如果注解的类型被标记为@Repeatable可以使用多次。可以通过使用@Target来限制使用一个注解的地点。例如你可以创建一个只能用在函数和属性上的可重复注解。认真的设计你的注解类型是很重要的,这样可以确保开发在使用发现它既灵活有强大

Last updated