@Repeatable 是需主动设计的机制,要求业务注解用 @Repeatable 声明容器、保留策略为 RUNTIME、Target 一致,容器注解必须有 value() 方法返回业务注解数组,运行时须用 getAnnotationsByType 获取全部实例。

Java 8 的 @Repeatable 不是“多写几次注解就自动生效”的语法糖,而是一套需主动设计、严格配对的机制——它让多个同类注解在代码中自然叠加,在运行时统一可读,真正实现语义清晰、配置即代码。
定义可重复注解本身
业务注解必须显式声明它可被重复,并指向一个容器类型:
- 用
@Repeatable(XXX.class)标注,括号内填容器接口名 - 保留策略(
@Retention)必须为RUNTIME,否则反射无法获取 -
@Target要明确指定适用位置(如METHOD、TYPE),后续容器注解必须完全一致 - 成员定义保持简洁,避免泛型或复杂嵌套,防止类型擦除导致容器 value 字段解析失败
配套定义容器注解
容器不是可选配件,而是编译器识别重复注解的必要桥梁:
- 容器注解必须有且仅有一个名为
value()的方法 - 该方法返回类型必须是业务注解的数组,例如
Role[] value(); -
@Retention和@Target必须与业务注解逐字相同,少一个ElementType.METHOD就会编译报错 - 容器名无强制规范,但建议用复数形式(如
Roles、Permissions),增强可读性
在方法或类上直接叠加使用
写法回归直觉,无需手动包裹:
立即学习“Java免费学习笔记(深入)”;
- 支持连续书写多个相同注解,如:
@Role("ADMIN") @Role("EDITOR") public void update() { } - 编译器自动将它们聚合成一个容器实例(如
@Roles({@Role("ADMIN"), @Role("EDITOR")})),对开发者透明 - 可在同一位置混合使用其他注解(如
@Transactional、@GetMapping),互不影响 - IDE 通常能正确提示、跳转和校验,但最终以
javac编译结果为准
运行时统一读取所有实例
反射获取方式决定能否真正拿到全部注解:
- ❌
method.getAnnotation(Role.class)—— 总是返回null或第一个(取决于 JVM 实现),不可靠 - ✅
method.getAnnotationsByType(Role.class)—— 推荐唯一方式,自动展开容器,返回完整数组 - ⚠️
method.getAnnotation(Roles.class)可用,但需额外调用.value()才能取出内容,增加冗余 - 拦截器、AOP 切面等通用逻辑应统一基于
getAnnotationsByType设计,避免硬编码容器解包
不复杂但容易忽略


















