Java注解扫描优化的核心是精准识别@Retention策略:仅RUNTIME注解可在运行时通过反射获取,SOURCE编译后消失,CLASS保留在字节码但不加载到内存;构建期可利用CLASS注解做零运行成本预处理;验证需用javap确认实际保留情况。

Java注解扫描优化的核心,不在“怎么扫”,而在“扫什么”——@Retention 就是那个决定要不要被扫、在哪个阶段能被扫的关键开关。它不参与扫描逻辑本身,但直接过滤掉大量无效注解,让扫描更轻、更快、更准。
Runtime注解才是反射扫描的唯一目标
只有声明为 @Retention(RetentionPolicy.RUNTIME) 的注解,才能在运行时通过 Class.getAnnotation()、Method.getAnnotation() 等反射 API 获取。其他两类注解对运行时扫描完全“不可见”:
- SOURCE:编译后就彻底消失,class 文件里连影子都没有;
-
CLASS(默认):虽保留在字节码中,但 JVM 加载类时不加载进内存,反射调用返回
null。
所以,如果你的扫描逻辑基于反射(比如 Spring 的组件扫描、自定义 AOP 切面、配置驱动的初始化器),那就只关注 RUNTIME 注解——其他一律跳过,不查、不解析、不构造代理对象。
避免无意义的全量扫描
很多框架或工具默认遍历所有注解,却没检查其保留策略,导致:
立即学习“Java免费学习笔记(深入)”;
- 反复调用
method.getAnnotations()得到一堆 null 或空数组; - 为 CLASS/SOURCE 注解做冗余元数据解析(如读取属性、校验结构);
- 增加 GC 压力和反射调用开销(哪怕只是判断
isAnnotationPresent())。
优化做法:先用 getDeclaredAnnotationsByType()(JDK 8+)或配合 Annotation.isAnnotationPresent() 快速判定是否存在 RUNTIME 注解;若不存在,直接跳过该元素。
构建期扫描可利用 CLASS 策略做预处理
如果扫描发生在构建阶段(如使用 Annotation Processor、Byte Buddy 或 ASM 修改字节码),那 CLASS 级注解就是黄金目标:
- 它们保留在 class 文件中,但不进运行时内存,零运行成本;
- 适合生成代码、注入日志、添加监控探针等“编译后即完成”的任务;
- 比 RUNTIME 更安全——不暴露给生产环境的反射入口,减少攻击面。
此时,扫描器应主动识别 @Retention(RetentionPolicy.CLASS) 注解,并在类加载前完成处理,无需等到应用启动。
验证注解是否真被保留,用 javap 最可靠
光看代码不够,实际 class 文件是否含注解,得靠工具验证:
- 执行
javap -v YourClass.class | grep -A5 "RuntimeVisibleAnnotations"→ 出现即为 RUNTIME; - 出现
RuntimeInvisibleAnnotations→ 对应 CLASS 策略; - 完全搜不到相关关键词 → 极可能是 SOURCE,或根本没生效(比如漏写 @Retention)。
这个步骤应在上线前或 CI 流程中加入,避免因策略误配导致运行时功能静默失效。


















