元注解是注解的设计说明书,决定自定义注解的适用范围、生命周期和可见性:@Target限定使用位置,@Retention控制保留策略,@Documented影响文档生成,@Inherited支持类继承传递,@Repeatable允许重复标注。

元注解不是“高级注解”,而是注解的“设计说明书”——它不参与业务逻辑,但决定了自定义注解能不能用、在哪用、用多久、被谁看见。
@Target:明确“谁可以贴这个标签”
它回答的是权限问题:你定义的注解,只允许加在类上?还是也能加在方法、参数、甚至泛型里?不设 @Target,编译器就默认它哪儿都能贴,容易引发误用。
- 常用组合示例:
@Target({ElementType.TYPE, ElementType.METHOD})表示既可标记整个控制器类,也可细化到某个接口方法 - 避免踩坑:如果注解本意是校验字段(如
@NotBlank),却漏写ElementType.FIELD,那加在属性上就会编译失败 - Java 8 新增的
TYPE_PARAMETER和TYPE_USE支持泛型和类型上下文标注,比如List<@NonNull String>
@Retention:决定“标签能活到什么时候”
这是注解能否被框架读取的关键开关。生命周期短了,反射拿不到;长了,又可能增加类加载开销。
-
RetentionPolicy.SOURCE:仅源码期有效,像@Override,编译完就扔,不进 class 文件 -
RetentionPolicy.CLASS:保留在字节码中,但 JVM 加载时不保留,适合 Lombok 这类编译期代码生成工具 -
RetentionPolicy.RUNTIME:唯一能让 Spring、MyBatis 等运行时框架通过反射读取的策略,90% 的自定义业务注解都必须选它
@Documented 与 @Inherited:影响“谁能看到这个标签”
这两个元注解解决的是可见性问题,一个对外(文档),一个对下(继承)。
立即学习“Java免费学习笔记(深入)”;
-
@Documented是“透明胶带”——加了它,Javadoc 生成时会把注解声明一并写进 HTML 文档,方便团队成员查阅语义 -
@Inherited是“向下传递开关”——仅对类级别注解生效,且只作用于 子类继承父类 场景(接口实现、组合关系都不触发),比如定义了@BaseConfig并加了 @Inherited,那class Sub extends BaseConfig {...}就自动拥有该注解
@Repeatable:支持“同一个地方贴多个同类标签”
Java 8 之前,同一位置不能重复使用相同注解,想表达多个值只能靠数组属性(如 @Roles({“ADMIN”, “USER”}))。@Repeatable 改变了这一点,让语法更自然。
- 使用前提:需配套定义一个“容器注解”,例如
@Roles的容器是@RolesList - 效果对比:
旧写法:@Permissions(@Permission("read"), @Permission("write"))
新写法:@Permission("read") @Permission("write") - 注意:反射读取时,
getAnnotationsByType(Permission.class)才能拿到全部,getAnnotation(Permission.class)只返回第一个


















