Java 注解处理概览
注解处理器如何在编译期读取注解并生成代码:与运行时反射的分工。
#type / concept
#status / growing
#tech / dev
#resource / java
[!info] 关联笔记
Java 注解处理概览
这个概念为什么出现
Dagger、MapStruct、部分 Lombok 机制、编译期校验器靠注解处理在 javac 期间生成源码/元数据,把成本挪到编译期。
[!abstract] 一句话理解 注解处理器在编译轮次中扫描注解并生成代码或报错;它不替代运行时反射,但可减少反射。
最小可观察示例
场景:理解保留策略决定谁能看见注解
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@interface Route { String value(); }
@Route("/health")
public class HealthController {
public static void main(String[] args) {
Route r = HealthController.class.getAnnotation(Route.class);
System.out.println(r.value());
}
}
javac HealthController.java && java HealthController
期望:
/health
说明:这是运行时可见注解演示;真正的处理器实现需独立模块实现 Processor SPI,由构建接入。
结合场景再看三个关注点
- SOURCE/CLASS/RUNTIME 保留策略不同。
- 处理器在编译期,要进注解处理器路径。
- 生成代码应可定位、可清理。
核心概念与准确模型
1. 处理器 API
javax.annotation.processing.Processor / AbstractProcessor
2. 轮次
多轮生成直到稳定。
3. 与反射分工
| 编译期处理 | 运行时反射 | |
|---|---|---|
| 时机 | javac | 运行 |
| 成本 | 编译变慢 | 运行开销 |
| 典型 | 映射器生成 | 框架扫描 |
边界情况与反直觉行为
- 增量编译与处理器兼容性。
- 生成代码与手写冲突。
- IDE 与命令行处理器路径不一致。
常见误区
[!warning] 常见误区:认为注解本身会“执行” 注解是元数据;行为来自处理器或运行时框架。
工程实践
- 处理器单独模块。
- 生成目录约定并 git 策略清晰。
- 失败信息指向用户源码位置。
- 版本化处理器与语言级别。
本节总结
- 编译期元编程
- 保留策略重要
- 与反射互补
自测题
- SOURCE 保留的注解运行时能否反射到?
- 注解处理的主要收益?
参考答案
- 通常不能。
- 提前生成/校验,降低运行时反射与配置错误。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| Annotation Processing | 文档(历史入口) | 概念 |
| javax.annotation.processing | API | 现代 API |