Java注解是可被程序读取的结构化元数据,其行为由@Target(限定适用位置)、@Retention(控制生命周期)、@Documented(决定是否生成文档)、@Inherited(控制类级继承)和@Repeatable(支持重复使用)共同定义。

Java注解不是装饰性标签,而是可被程序读取并响应的结构化元数据。真正用好注解,关键在于理解并合理组合元注解——它们共同构成了一套“行为契约”,决定注解在哪能用、能活多久、是否可见、能否继承、是否可重复。
@Target:明确注解的适用边界
它像一道准入门槛,防止注解被错误地加在不支持的位置上。编译器会据此做静态检查,一旦越界直接报错,避免运行时语义模糊或解析失败。
- 标注类、接口、枚举等整体结构,用 ElementType.TYPE(如 @RestController)
- 控制方法行为,选 ElementType.METHOD(如 @Transactional)
- 绑定参数处理逻辑,用 ElementType.PARAMETER(如 @RequestBody)
- 需要精细干预类型使用场景(比如泛型、强制转换),启用 ElementType.TYPE_USE(Java 8+,用于类型级校验)
- 若允许多处使用,必须显式列出多个值,例如
@Target({METHOD, TYPE, FIELD})
@Retention:掌控注解的生命周期
它决定了注解信息能“活”到哪个阶段,直接影响你能否通过反射获取它,也决定了它适合哪类工具链介入。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- RetentionPolicy.SOURCE:仅源码存在,编译后消失。适合编译期检查,如 @Override、@SuppressWarnings
- RetentionPolicy.CLASS:保留在 .class 文件里,但 JVM 不加载。常用于字节码增强工具(ASM、ByteBuddy)做无侵入改造
- RetentionPolicy.RUNTIME:全程保留,是框架开发的标配。Spring、MyBatis 等靠它在运行时动态注入、路由、事务管理
- 自定义注解若需反射读取,必须设为 RUNTIME;否则反射调用 getAnnotation() 将始终返回 null
@Documented 与 @Inherited:管理元数据的传播逻辑
这两个元注解不改变功能,只影响元数据如何被“看见”和“传递”,属于协作层面的设计契约。
立即学习“Java免费学习笔记(深入)”;
- @Documented 表示该注解应出现在生成的 Javadoc 中。团队协作时,它让接口文档自带语义,比如自定义的 @ApiVersion 或 @Experimental,开发者看文档就能知道约束条件
- @Inherited 仅对类级注解生效,且仅作用于子类继承关系(不传递给方法或字段)。适用于统一基类策略,例如 @SecuredBase,子类自动获得安全配置;但 @Override 这类方法级注解不会被继承
- 两者都不影响运行逻辑,但缺失时可能造成文档缺失或继承预期不符,属于易忽略却重要的工程细节
@Repeatable:解除单次使用的硬性限制
默认情况下,同一注解不能重复加在同一个目标上。@Repeatable 打破这一限制,但需配套设计容器注解,形成语义聚合。
- 典型场景如权限控制:
@RolesAllowed("ADMIN")和@RolesAllowed("USER")可共存,底层由@RolesAllowed.List自动聚合 - 容器注解的 value 属性必须返回原注解数组,且两者的 @Target 和 @Retention 必须完全一致
- 使用时无需手动写容器,JVM 会自动识别并转换;但定义时容易漏掉容器注解或属性签名不匹配,导致编译失败

















