Java 8可重复注解直接解决同一元素多次使用相同注解的语法限制,如权限控制中可自然叠加@RequireRole("ADMIN")、@RequireRole("EDITOR")等,无需容器包装;定义需两步:被重复注解标注@Repeatable(容器类),容器注解value字段为该注解数组类型;运行时通过getAnnotationsByType()直接获取全部实例,配合AOP可统一鉴权。
java 8 引入了可重复注解(repeatable annotations),它能直接解决“在同一个类或方法上多次使用同一注解”的语法限制问题。权限控制场景中,比如需要为一个接口同时声明 @requirerole("admin")、@requirerole("editor")、@requirepermission("user:delete") 等多个权限标签时,若不借助 repeatable,只能靠容器注解(如 @requireroles({@requirerole("admin"), @requirerole("editor")}))来包裹,既冗长又破坏语义直观性。
定义可重复的权限注解
要让 @RequireRole 可重复,需两步:先定义注解本身,再声明其“容器注解”。关键在于 @Repeatable 元注解必须指向一个**单值数组类型**的容器注解,且该容器的 value 字段类型必须与被重复注解一致。
例如:
// 1. 被重复的注解@Repeatable(RequireRoles.class)@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface RequireRole { String value();}
// 2. 容器注解(命名惯例:复数形式)@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface RequireRoles { RequireRole[] value();}
在类或方法上直接叠加使用
定义完成后,即可在目标元素上自然地多次写同一个注解,无需手动包装:
@RequireRole("ADMIN")@RequireRole("EDITOR")@RequirePermission("post:publish")@RequirePermission("post:review")
编译器会自动将它们收集到对应的容器注解中(如 @RequireRoles({@RequireRole("ADMIN"), @RequireRole("EDITOR")})),对运行时读取完全透明。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
运行时统一提取所有重复注解
反射 API 提供了 getAnnotationsByType() 方法,可直接获取全部重复实例,无需手动解包容器:
AnnotatedElement element = YourController.class.getMethod("update");RequireRole[] roles = element.getAnnotationsByType(RequireRole.class);RequirePermission[] perms = element.getAnnotationsByType(RequirePermission.class);
这比传统方式(先 getAnnotation(RequireRoles.class),再取 .value())更简洁、安全,也避免空指针或类型判断错误。
配合 AOP 或拦截器实现统一鉴权逻辑
在 Spring 中,可结合 @Aspect 切入点匹配 @annotation(RequireRole) 或 @args,但更推荐在环绕通知中一次性提取所有权限注解:
- 用
joinPoint.getSignature().getDeclaringType()和getDeclaringMethod()获取目标元素 - 调用
getAnnotationsByType(RequireRole.class)和getAnnotationsByType(RequirePermission.class)分别收集角色与权限要求 - 根据当前用户凭证批量校验,任一不满足即抛出
AccessDeniedException
这样既保持注解语义清晰,又让鉴权逻辑集中、可扩展——新增权限类型只需加新注解 + 少量校验分支,不改动核心流程。

















