javac在注解处理阶段自动调用process()方法,该阶段位于解析与填充符号表之后、语义分析之前;编译器先加载处理器、初始化环境、收集带注解元素,再传入annotations和roundEnv参数调用process(),返回true且生成新文件会触发多轮编译。

javac 在编译过程中,会在“注解处理阶段”主动调用你写的 process() 方法,这个调用不是你手动触发的,而是编译器按固定流程自动完成的。
编译流程中明确的执行时机
javac 的编译分三步:解析与填充符号表 → 注解处理 → 语义分析与字节码生成。其中“注解处理”是独立且可插拔的一环,发生在语法树构建之后、类型检查之前。只要源码里用了你声明支持的注解(比如 @GenerateBuilder),javac 就会在这个阶段启动你的处理器,并调用其 process() 方法。
调用前的准备动作
在真正执行 process() 前,javac 已经完成了几件事:
- 通过
META-INF/services/javax.annotation.processing.Processor或构建工具配置,定位并加载你的处理器类; - 调用
init(ProcessingEnvironment)初始化上下文,把Filer、Messager、Elements等关键工具注入进去; - 扫描所有源文件,收集被你支持的注解标记的元素(如类、方法、字段),封装成
Element对象; - 把这批元素和注解类型集合一起打包进
RoundEnvironment实例。
实际调用过程
javac 内部会创建一个处理器实例(注意:每个处理器在单次编译中是单例),然后执行:
使用 ImageMagick 的 convert 和 mogrify 命令进行批量图像处理,支持调整大小、裁剪、水印和格式转换。与 libvips 集成以实现高性能缩略图生成。
立即学习“Java免费学习笔记(深入)”;
processor.process(annotations, roundEnv);
其中:
-
annotations是当前轮次中该处理器声明要处理的注解类型集合(例如Set.of(MyAnnotation.class)); -
roundEnv提供了getElementsAnnotatedWith()等方法,让你能拿到所有被这些注解标记的源码元素; - 返回值
boolean表示本轮是否产生了新文件——如果返回true且生成了新的.java文件,javac 会开启下一轮编译(re-round),重新扫描包括新文件在内的全部源码,直到某轮没生成新文件才结束注解处理阶段。
多轮编译(Round)机制
这是容易忽略的关键点:
- 第一轮只处理原始源码中的注解;
- 如果你在
process()中用Filer.createSourceFile()生成了新.java文件,javac 会把它加入待编译队列; - 第二轮开始,新文件也会被解析,其中若又用了你支持的注解,
process()会被再次调用; - 这种机制让 Lombok、Dagger 这类框架可以递归生成代码(比如 Builder 里又用到另一个注解)。


















