注解处理器和 编译时注解处理器(APT)的区别
目录
注解处理器和 编译时注解处理器(APT)的区别
编译时注解处理器(APT)
编译时注解处理器(APT)是Java编译器的扩展,在编译阶段对源代码进行处理。它的主要作用可以分为以下几个核心方面:
- 代码生成(最主要的作用)
- 编译时验证和约束检查
- 元数据收集和索引生成
- 性能优化:避免运行时反射,取代运行时注解扫描
- 跨语言/协议代码生成
- 依赖注入配置生成
- 减少人工错误
编译时处理器的核心价值:
- ✅ 性能优化 - 编译时生成,避免运行时反射开销
- ✅ 类型安全 - 编译时检查,早发现错误
- ✅ 代码简洁 - 减少样板代码,专注业务逻辑
- ✅ 维护性好 - 生成的代码一致可靠
- ✅ 开发效率 - 自动生成重复模式
- ✅ 框架扩展 - 让框架更强大但透明
对比
| 术语 | 准确含义 | 是否同一概念 |
|---|---|---|
| 注解处理器 | 广义:任何处理注解的机制 | 包含编译时和运行时 |
| APT | 特指:JSR 269,编译时处理 | ✅ 是编译时注解处理器 |
| 编译时注解处理器 | 准确描述:在编译时处理注解 | ✅ 就是APT |
| 运行时注解处理器 | 通过反射处理RUNTIME注解 | ❌ 不是APT |
// 编译时注解处理器(真正的Processor):
源代码 → 编译 → [处理器介入] → 生成新代码 → 继续编译 → .class文件
↑
编译时执行,javac调用
// 运行时反射处理(不是Processor):
程序启动 → 框架初始化 → 反射扫描类 → 检查注解 → 创建Bean
↑
运行时执行,你的代码调用
编译时处理器:一次性的,影响编译速度
-
生成的代码运行时直接使用,无开销
-
编译时处理器需要注册:SPI机制
-
META-INF/services/javax.annotation.processing.Processor
-
com.example.MyAnnotationProcessor
-
com.example.AnotherProcessor
-
-
运行时反射处理:每次启动都执行
-
反射调用有性能开销
-
运行时处理什么都不需要注册
编译时注解处理器(APT)历史演变
Java 5 (2004):APT诞生
# 最初叫APT工具
apt -factory MyAnnotationProcessorFactory MyClass.java
# apt是一个独立工具
Java 6 (2006):集成到javac
# 集成到标准编译器
javac -processor MyProcessor MyClass.java
# apt命令被废弃,但"APT"这个名字留下了
Java 8+ (2014):标准化
// 现在标准叫法是"注解处理器"
// 但很多人仍习惯叫"APT"
技术上的准确区分
实际是包含关系:
注解处理器(Annotation Processors)
├── 编译时注解处理器(APT/JSR 269)✅ 我们通常讨论的
│ ├── 生成代码的处理器(如Google AutoValue)
│ ├── 检查代码的处理器(如Error Prone)
│ └── Lombok(特殊的,修改AST)
└── 运行时注解处理器(通过反射)❌ 不叫APT
代码示例对比理解
编译时注解处理器(标准APT):
// 1. 定义注解
@Retention(RetentionPolicy.SOURCE) // 必须是SOURCE或CLASS
public @interface GenerateInterface {}
// 2. 实现处理器(这就是APT) 必须继承AbstractProcessor,在META-INF/services注册
@SupportedAnnotationTypes("*.GenerateInterface")
@SupportedSourceVersion(SourceVersion.RELEASE_11)
public class MyAnnotationProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// 在编译时运行,生成新文件
generateJavaFile();
return true;
}
}
// 3. 使用
@GenerateInterface
public class MyClass {} // 编译时生成 MyClassInterface.java
运行时注解处理器(不是APT):
其实严格说:行业里根本不存在所谓的"运行时注解处理器"这个标准术语,只有"使用反射处理运行时注解"这个操作。
反射处理注解:普通Java代码 + 反射API。通过反射处理RUNTIME注解
// 这是通过反射,不是APT!
@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimeAnnotation {}
// 运行时通过反射处理
public class RuntimeProcessor {
public static void main(String[] args) {
Class<?> clazz = Dog.class;
RuntimeAnnotation ann = clazz.getAnnotation(RuntimeAnnotation.class);
// 运行时逻辑...
}
}
浙公网安备 33010602011771号