# 注解的保留策略

保留策略(Retention Policy)

提到策略。那当然想到的就是36计。计谋都有穷尽的时候何况策略。保留策略在java中一定是枚举变量的存在。

package java.lang.annotation;
1

# RetentionPolicy枚举源码

/**
 * Annotation retention policy.  The constants of this enumerated type
 * describe the various policies for retaining annotations.  They are used
 * in conjunction with the {@link Retention} meta-annotation type to specify
 * how long annotations are to be retained.
 *
 * 注解保留策略。该枚举类型的常量描述了保留注解的各种策略。
 * 它们与 {@link Retention} 元注解类型结合使用,以指定注解应被保留多长时间。
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     * 注解将被编译器丢弃。
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     * 注解将由编译器记录在类文件中,但在运行时不需要被虚拟机保留。这是默认行为。
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     * 注解将由编译器记录在类文件中,并在运行时由虚拟机保留,因此可以通过反射读取。
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# RetentionPolicy枚举值总结表

策略值 生命周期 编译后是否保留 运行时是否可用 默认行为 应用在哪些地方? 解决了什么问题? 作用是什么? 具体框架/注解示例
SOURCE 源码级别 ❌ 否 ❌ 否 - 1. 编译器 2. IDE工具 3. 代码生成器 4. 静态分析工具 1. 防止编码错误 2. 减少样板代码 3. 统一代码规范 4. 自动化代码生成 1. 语法检查:验证代码正确性 2. 警告管理:控制编译器警告 3. 代码生成:自动创建重复代码 4. 静态分析:发现潜在问题 1. Java内置@Override(方法重写检查) 2. Java内置@SuppressWarnings(抑制警告) 3. Lombok@Getter/@Setter(自动生成getter/setter) 4. Android@NonNull(空值检查) 5. FindBugs@Nullable(空指针检查)
CLASS 类文件级别 ✅ 是 ❌ 否 默认值 1. 字节码操作框架 2. AOP框架 3. 类加载器 4. 编译时处理器 1. 字节码增强 2. 性能优化 3. 横切关注点分离 4. 编译时代码修改 1. 字节码处理:在编译后修改类文件 2. AOP实现:方法拦截和增强 3. 代理生成:创建动态代理类 4. 性能监控:注入监控代码 1. AspectJ@Aspect(切面定义) 2. ASM框架:字节码操作注解 3. ByteBuddy:动态类生成注解 4. Spring AOP:部分内部注解 5. JaCoCo:代码覆盖率分析注解
RUNTIME 运行时级别 ✅ 是 ✅ 是 - 1. 依赖注入框架 2. ORM框架 3. Web框架 4. 序列化框架 5. 配置框架 1. 依赖管理 2. 对象关系映射 3. 请求路由 4. 数据转换 5. 运行时配置 1. IoC容器:管理对象生命周期和依赖 2. 数据映射:数据库表与对象映射 3. 请求处理:HTTP请求与方法映射 4. 序列化:对象与JSON/XML转换 5. 配置驱动:基于注解的配置管理 1. Spring@Component(组件扫描) 2. Spring@Autowired(依赖注入) 3. JPA/Hibernate@Entity(实体映射) 4. Spring MVC@RequestMapping(请求映射) 5. Jackson@JsonProperty(JSON属性映射) 6. Spring Boot@Configuration(配置类) 7. JUnit@Test(测试方法) 8. Swagger@ApiOperation(API文档)

# 详细说明

# 1. SOURCE(源码级)

  • 特点:仅在源代码中存在,编译后完全消失

  • 使用方式:只能通过注解处理器(Annotation Processor)在编译时访问

  • 典型示例

    @Override  // 编译时检查方法是否真的重写了父类方法
    @SuppressWarnings("unchecked")  // 告诉编译器忽略特定警告
    @Deprecated  // 标记已过时的方法或类
    
    1
    2
    3

# 2. CLASS(类文件级)

  • 特点:保留在 .class 字节码文件中,但不加载到 JVM 内存

  • 使用方式:通过字节码操作框架(如 ASM、ByteBuddy)在类加载前处理

  • 典型示例

    // 很多框架的内部注解使用此策略
    // 例如某些 AOP 框架在编译时织入代码
    
    1
    2

# 3. RUNTIME(运行时级)

  • 特点:完全保留,可通过反射 API 在运行时获取

  • 使用方式:使用 Class.getAnnotations()Method.getAnnotation() 等方法

  • 典型示例

    @RestController  // Spring MVC 控制器
    @RequestMapping("/api")
    public class MyController {
        @GetMapping("/users")
        @ResponseBody
        public List<User> getUsers() { ... }
    }
    
    1
    2
    3
    4
    5
    6
    7

# 保留策略选择建议

场景 推荐策略 原因
仅编译时检查 SOURCE 不增加运行时开销,保持类文件简洁
框架需要处理字节码 CLASS 框架可在类加载时修改字节码,但运行时不需要
运行时依赖注解 RUNTIME 框架需要通过反射读取注解配置
不确定未来用途 RUNTIME 保持灵活性,可随时通过反射访问

# 代码示例对比

// SOURCE 策略 - 编译后消失
@Override  // RetentionPolicy.SOURCE
public String toString() { return "example"; }

// CLASS 策略 - 保留在类文件中但不加载到 JVM
@SomeAspectAnnotation  // RetentionPolicy.CLASS - AspectJ 等使用
public void someMethod() { }

// RUNTIME 策略 - 可通过反射获取
@Component  // RetentionPolicy.RUNTIME - Spring 框架
public class MyService {
    @Autowired  // RetentionPolicy.RUNTIME
    private MyRepository repository;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 内存与性能考虑

  • SOURCE:无运行时开销
  • CLASS:轻微磁盘空间开销(类文件稍大),无内存开销
  • RUNTIME:有内存开销(注解对象常驻内存),反射调用有性能开销

选择适当的保留策略有助于平衡功能需求与系统性能。

Last Updated: 4/3/2026, 6:47:37 AM