@Retention的三种策略决定注解生命周期:SOURCE仅存于源码,编译时丢弃;CLASS保留在字节码但运行时不加载;RUNTIME保留在运行时,可通过反射访问,是框架功能(如Spring注入)的基础。

@Retention 是 Java 中用来指定注解保留策略的元注解,它决定了一个注解在哪个阶段还“存在”——是只在源码里、编译后就消失,还是能被 JVM 在运行时读取。它的值由 RetentionPolicy 枚举决定,共三种: SOURCE、CLASS、RUNTIME。
1. @Retention(RetentionPolicy.SOURCE) —— 仅保留在源码阶段
这类注解在编译完成(.class 文件生成)后就被丢弃,不会写入字节码。适合用于编译器检查或代码生成工具(如 Lombok 的 @Getter 默认就是 SOURCE 级别,但 Lombok 通过编译器插件提前处理)。
常见用途:
- 触发编译警告或错误(如自定义
@Deprecated替代品) - 配合注解处理器(
javax.annotation.processing.Processor)生成额外代码 - IDE 提示用的标记(如
@SuppressWarnings就是 SOURCE 级别)
无法通过反射获取,运行时 clazz.isAnnotationPresent(...) 返回 false。
立即学习“Java免费学习笔记(深入)”;
2. @Retention(RetentionPolicy.CLASS) —— 保留在 .class 文件中,但不加载进 JVM
注解会写入编译后的字节码,但 JVM 在类加载时不会将其加入运行时内存(即 Class.getAnnotations() 拿不到)。这个级别很少由开发者直接使用,更多是框架或字节码增强工具(如 ASM、Byte Buddy)在类加载前读取并修改字节码时用到。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
注意:
- Java 反射 API 完全不可见该注解
- 不能用
isAnnotationPresent()或getAnnotation()检查 - 需要借助字节码库(如 ASM)解析 .class 文件才能读取
3. @Retention(RetentionPolicy.RUNTIME) —— 运行期可用,最常用
这是唯一能让注解在程序运行时通过反射访问的策略。JVM 加载类时会将这些注解一并加载进内存,你可以用标准反射 API 获取它们。
典型用法:
- Spring 的
@Autowired、@RequestMapping - JPA 的
@Entity、@Column - JUnit5 的
@Test、@BeforeEach
示例:
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecution {
String value() default "";
}
<p>public class Service {
@LogExecution("user login")
public void login() { /<em> ... </em>/ }
}</p><p>// 运行时读取
Method m = Service.class.getMethod("login");
if (m.isAnnotationPresent(LogExecution.class)) {
LogExecution ann = m.getAnnotation(LogExecution.class);
System.out.println(ann.value()); // 输出 "user login"
}</p>怎么选?关键看谁需要读取它
一句话判断:
- 只有编译器/IDE/注解处理器需要 → 选
SOURCE - 字节码工具(非反射)需要操作 → 选
CLASS - 运行时逻辑(如依赖注入、权限校验、日志拦截)需要反射读取 → 必须选
RUNTIME
没加 @Retention 的注解,默认是 CLASS,但建议显式声明,避免误解。

















