关键在于使用@Retention(RetentionPolicy.SOURCE),该策略使注解仅保留在源码中,编译时丢弃,不写入.class文件,无法反射获取,适用于编译期检查、IDE提示或APT处理。

Java 中编写只能在源码级别生效的自定义注解,关键在于将注解的 @Retention 策略设为 RetentionPolicy.SOURCE。这类注解仅保留在 Java 源文件中,编译时即被丢弃,不会进入字节码(.class 文件),因此运行时完全不可见,也无法通过反射获取。
定义 SOURCE 级别注解
使用 @Retention(RetentionPolicy.SOURCE) 即可确保注解只存在于源码阶段。它常用于编译期检查、代码生成提示或 IDE 辅助(如 Lombok 的 @Cleanup 风格,但注意 Lombok 实际依赖编译插件,并非纯 SOURCE)。
- 必须显式指定
@Retention(RetentionPolicy.SOURCE) - 通常搭配
@Target明确作用位置(如ElementType.METHOD、ElementType.TYPE等) - 不能添加
@Documented或@Inherited(它们对 SOURCE 注解无意义,编译器会忽略或报错)
一个典型示例
下面是一个仅在源码中起标记作用、编译后消失的注解:
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Experimental {
String value() default "";
}你可以在方法或类上使用它:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
@Experimental("v2.0")
public void newFeature() { /* ... */ }但编译完成后,反编译 .class 文件或用 getAnnotations() 反射调用,都找不到该注解 —— 它已彻底移除。
它能做什么、不能做什么
能做的:
- 配合编译器插件(如 Annotation Processing Tool,APT)在编译期做静态检查(例如禁止调用某方法)
- 作为开发约定标记,供 IDE 高亮、警告或代码分析工具识别(如 SonarQube、ErrorProne)
- 生成文档注释或辅助代码审查(虽不参与运行,但提升可读性)
不能做的:
- 无法在运行时通过反射读取(
method.getAnnotation(Experimental.class)总是返回 null) - 不能被 Spring、Jackson 等运行时框架识别和处理
- 不能用于 AOP、动态代理等依赖运行时注解的机制
与其它保留策略对比
SOURCE:仅源码 → 编译即丢弃
CLASS:源码 + 字节码 → 类加载时不进 JVM 方法区(默认)
RUNTIME:源码 + 字节码 + 运行时 → 可反射访问

















