runtime注解会增加类加载时间、元空间占用及反射开销;class注解仅增大字节码体积,不影响运行时;source注解编译后即消失,零运行时成本。选型依据:运行时反射→runtime;构建工具扫描→class;编译检查/代码生成→source。

Java 类加载器在加载类时,会解析 class 文件中的元数据,包括注解信息。而 @Retention 策略直接决定这些注解是否进入 JVM 运行时内存——这直接影响类加载速度、内存占用和后续反射开销。
RUNTIME 注解会拖慢类加载,尤其在类数量多的系统中
当注解设为 RetentionPolicy.RUNTIME,JVM 必须在加载类时解析并缓存其注解结构(如 RuntimeVisibleAnnotations 属性),这部分元数据会常驻方法区(或元空间),且随类一起被 GC Roots 引用。实测表明:
- 每个 RUNTIME 注解平均增加 class 文件体积 30–120 字节(含常量池项、属性表长度);
- 百万级类规模下,启动阶段类加载时间延长 8%–15%,元空间占用上升明显;
- Spring Boot 2.6+ 默认禁用全量
@Component扫描,改用spring.components.index,正是为了规避 RUNTIME 注解遍历带来的加载瓶颈。
CLASS 注解不参与运行时,但会影响字节码体积和构建工具链RetentionPolicy.CLASS 是默认策略,注解写入 class 文件的 RuntimeInvisibleAnnotations 属性,JVM 加载时不解析、不缓存,无反射开销。但它仍带来轻微成本:
- class 文件体积略有增大(比 SOURCE 多几个字节);
- 构建阶段若使用 ASM、Byte Buddy 等工具扫描注解,会触发额外 I/O 和解析逻辑;
- 不影响运行时性能,适合“编译即用、运行即弃”的场景,比如 Dagger 的依赖图生成、Android 资源标记。
SOURCE 注解对类加载零干扰RetentionPolicy.SOURCE 注解在 javac 编译完成后就彻底消失,不会出现在 class 文件里,更不会被类加载器看到:
- 不增加任何字节码体积;
- 不触发任何 JVM 元数据解析流程;
- 适用于纯编译期行为,例如
@Override、自定义 Lint 规则、Lombok 的@Getter(由注解处理器生成代码,而非运行时读取)。
怎么选?看注解到底谁来读、什么时候读
- 需要运行时通过
getAnnotation()或 AOP 切面动态获取 → 必须RUNTIME(如@Transactional、自定义@Audit); - 只供构建工具(APT、ASM、Gradle 插件)在加载前分析 →
CLASS更安全轻量; - 仅用于编译检查、IDE 提示或生成 Javadoc →
SOURCE是最优解,没理由用更重的策略。
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











