自定义编译期标记注解需设@retention为source或class、@target限定作用位置,并配合apt处理器实现编译时校验或代码生成;不应用runtime,推荐加@documented和javadoc。

自定义编译期标记注解,核心是让注解只在源码或 class 文件阶段存在,运行时不可见,且不依赖反射处理——这类注解通常用于编译器检查或 APT(Annotation Processing Tool)生成代码。
@Retention 设为 SOURCE 或 CLASS
这是决定“编译期标记”属性的关键。必须明确指定保留策略:
- SOURCE:注解仅保留在 .java 源文件中,编译后彻底丢弃。适合纯编译检查类场景,如自定义 @NonNullCheck、@ApiVersion 等,由注解处理器在编译时校验并报错。
- CLASS(默认值):注解写入 .class 文件,但 JVM 加载时不保留,运行时无法通过反射获取。适合需要构建工具(如 Gradle/Maven 插件)或字节码增强工具(如 Byte Buddy)读取的场景。
不要用 RUNTIME,否则就不是“编译期标记”,而是运行时注解了。
@Target 明确限定作用位置
告诉编译器这个标记能加在哪。常见组合有:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- ElementType.METHOD:标记某个方法需做参数非空校验
- ElementType.PARAMETER:标记方法参数不可为 null
- ElementType.TYPE:标记整个类属于某个 API 版本
- ElementType.PACKAGE:配合 package-info.java 使用,标记整个包的特性(如 @DeprecatedPackage)
避免宽泛设置,比如只用于方法就别写 @Target({TYPE, METHOD, FIELD}),否则容易误用。
搭配注解处理器(APT)实现真正功能
编译期注解本身不执行逻辑,必须靠 APT 在 javac 编译过程中扫描并响应:
- 编写一个继承 AbstractProcessor 的处理器类
- 在 process() 方法中遍历被该注解标记的元素,做校验、生成辅助类、输出警告或错误
- 通过 Messager 输出编译期提示(warning / error),例如:
messager.printMessage(Diagnostic.Kind.ERROR, "@ApiV2 不能用于私有方法", element); - 在 resources/META-INF/services/javax.annotation.processing.Processor 中声明处理器全类名
典型例子:Lombok 的 @Data、@Builder 就是靠 APT 在编译期生成 getter/setter/构造器代码;Android 的 ButterKnife 早期也用 APT 生成绑定代码。
可选但推荐:加上 @Documented 和清晰 Javadoc
虽然不影响编译行为,但能提升协作体验:
- @Documented:确保该注解出现在生成的 JavaDoc 中,方便团队成员查阅用途
- 为注解类写明 Javadoc,说明适用场景、约束条件、典型误用示例
- 注解元素尽量设合理默认值(如
String value() default "";),减少使用时冗余写法
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










