@Repeatable注解通过容器注解实现同一元素上多次声明相同注解,提升语义清晰度与可维护性;需三步:业务注解标注@Repeatable、定义含value字段的容器注解、按规范使用。

Java 8 引入的 @Repeatable 注解,解决了“同一个元素上不能重复使用相同注解”的限制。它不是直接让你写两次 @MyAnno 就生效,而是需要配合一个「容器注解」来实现语义上的多次标注。
为什么需要 @Repeatable?
在 Java 8 之前,如果想在一个方法上标记多个同类型注解(比如多个权限要求、多个校验规则),只能靠定义一个数组型注解字段,例如:
@Permissions({@Permission("read"), @Permission("write")})
这样写不够直观,也不符合“声明式表达多个独立语义”的直觉。@Repeatable 让你可以真正写成:
@Permission("read")<br>@Permission("write")<br>public void doSomething() { ... }
语义清晰,也更易读、易维护。
@Repeatable 的实现三步走
要让自定义注解支持重复,必须满足三个条件:
-
定义你的业务注解,并在其上标注
@Repeatable(XXX.class),括号里填容器注解的类名 -
定义对应的容器注解:必须是
@Retention和@Target与业务注解一致;必须有一个名为value的MyAnno[]类型字段 -
确保容器注解的
value字段返回类型是业务注解数组,且名称严格为value
一个完整可运行的例子
目标:在方法上标注多个 @Role,表示该方法需多个角色才能访问。
// 1. 业务注解<br>@Repeatable(Roles.class) // 关键:指定容器<br>@Retention(RetentionPolicy.RUNTIME)<br>@Target(ElementType.METHOD)<br>public @interface Role {<br> String value();<br>}
// 2. 容器注解<br>@Retention(RetentionPolicy.RUNTIME)<br>@Target(ElementType.METHOD)<br>public @interface Roles {<br> Role[] value(); // 名字必须叫 value,类型必须是 Role[]<br>}
// 3. 使用方式(合法)<br>@Role("ADMIN")<br>@Role("OPERATOR")<br>public void deleteUser() { }
此时通过反射获取该方法的注解时:
Method m = ...;<br>Role[] roles = m.getAnnotationsByType(Role.class); // ✅ 可直接获取所有 @Role 实例<br>// 或者<br>Roles container = m.getAnnotation(Roles.class); // ✅ 也能拿到容器
注意事项和常见坑
- 容器注解的
@Target必须包含业务注解所支持的所有位置,否则编译报错 - 如果只用反射调用
getAnnotation(Class)(非 ByType 版本),只能拿到容器注解,拿不到单个@Role - IDE(如 IntelliJ)对 @Repeatable 支持良好,但旧版编译器或某些构建插件可能识别异常,建议统一用 JDK 8+
- Spring 等主流框架已原生支持 @Repeatable,比如
@Bean、@Scope都已改造,可放心用于配置类

















