要让自定义注解支持重复使用,必须配合@repeatable和容器注解:容器注解需声明value元素且类型为目标注解数组、@target与@retention一致;目标注解用@repeatable指向容器;使用时可重复声明,反射通过getannotationsbytype获取。

要让自定义注解支持在同一个位置重复使用,必须配合 @Repeatable 和一个“容器注解”一起使用。Java 不允许直接多次声明同一注解类型(比如 @Role("admin") @Role("user")),但通过 @Repeatable 可以绕过这个限制,前提是定义好对应的容器注解。
1. 容器注解必须是数组类型且返回目标注解类型
容器注解本身是一个普通注解,但它必须满足两个硬性要求:
- 只声明一个名为
value的元素(也可以用value以外的名字,但需在@Repeatable中显式指定) - 该元素的类型必须是目标注解类型的数组(例如
Role[] value()) - 容器注解的
@Target和@Retention必须与目标注解一致,否则编译报错
示例容器注解:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Roles {
Role[] value();
}
2. 目标注解上标注 @Repeatable 并指向容器注解
在你要重复使用的注解(如 @Role)上,用 @Repeatable 指明它对应的容器注解类名(注意是类字面量,不是字符串):
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Roles.class) // ← 关键:关联到容器注解
public @interface Role {
String value() default "";
}
3. 使用时可重复写,运行时自动转为容器形式
代码中可以直接多次使用 @Role:
@Role("admin")
@Role("editor")
public class ArticleService { ... }
此时 JVM 会将这两个 @Role 自动包装成一个 @Roles({@Role("admin"), @Role("editor")}) 存入元数据。反射获取时有两种方式:
- 调用
getAnnotationsByType(Role.class)→ 返回Role[](推荐,自动解包) - 调用
getAnnotation(Roles.class)→ 返回Roles实例,再取value()数组
注意:getAnnotations()(不带 ByType)不会返回重复注解,因为它只返回显式声明的注解(即容器注解),而原始重复注解已被“隐藏”。
4. 容器注解名没有强制约定,但建议遵循命名惯例
虽然 Java 不强制要求容器注解名以复数结尾(如 Roles),但这是通用实践,便于理解。只要类型匹配、元注解一致,任何合法类名都可作为容器。不过若违反 @Target 或 @Retention 一致性,编译器会直接报错,无需等到运行时。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










