Java Compiler API


一、背景与定位

1. 诞生背景

Java 6(JSR 199) 之前,Java 的编译能力主要以两种形式存在:

  1. 命令行工具javac
  2. IDE / 构建工具内部实现(如 Ant、IDEA、Eclipse 的编译器)

这些方式存在明显局限:

  • 无法在 运行时 直接进行 Java 源码编译
  • 无法在 服务端 / 工具链 / DSL / 插件系统 中嵌入标准编译能力
  • 缺乏统一、标准、可扩展的编译 API

Java Compiler API(JSR 199) 的目标是:

javac 的核心能力以 标准化、可编程 API 的形式暴露出来。


二、整体架构与核心组件

Java Compiler API 主要位于:

复制代码
javax.tools

其整体结构可以理解为一个 可嵌入式编译器框架

!\[1_1Java Compiler API.png]

!\[1_2Java Compiler API.png]

1. 核心接口总览

接口 / 类 作用
JavaCompiler 编译器主入口
ToolProvider 获取系统编译器
CompilationTask 一次编译任务
JavaFileObject 抽象的"源码/字节码文件"
JavaFileManager 文件管理与输出控制
StandardJavaFileManager 默认文件系统实现
Diagnostic / DiagnosticCollector 编译错误、警告信息
FileObject 更通用的文件抽象

三、核心接口详解

1. ToolProvider & JavaCompiler

java 复制代码
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
关键说明
  • 仅在 JDK 中可用

  • 如果运行环境是 JRE / jlink runtime ,该方法返回 null

  • 本质上获取的是 javac 的程序化入口


2. JavaFileObject:源码与字节码的统一抽象

java 复制代码
public interface JavaFileObject extends FileObject

它抽象了:

  • .java 源码
  • .class 字节码
  • 内存中的"虚拟文件"
常见实现
  • SimpleJavaFileObject
  • StandardJavaFileManager 内部实现

这也是 "内存编译""动态代码生成" 的基础。


3. JavaFileManager:编译输入 / 输出控制中心

负责:

  • 源文件的查找
  • classpath / module-path 的解析
  • 编译产物(.class)的输出位置
java 复制代码
StandardJavaFileManager fm =
    compiler.getStandardFileManager(diagnostics, null, null);
高级用法
  • 自定义 JavaFileManager
  • .class 输出到:
    • 内存
    • 数据库
    • 网络
    • 自定义 ClassLoader

4. CompilationTask:一次完整的编译任务

java 复制代码
JavaCompiler.CompilationTask task =
    compiler.getTask(
        writer,
        fileManager,
        diagnostics,
        options,
        classes,
        compilationUnits
    );
参数语义
参数 含义
writer 编译器输出(stdout/stderr)
fileManager 文件管理
diagnostics 错误收集
options -classpath-source
classes 注解处理目标类
compilationUnits 待编译源码

5. Diagnostic:编译错误的结构化表示

java 复制代码
for (Diagnostic<?> d : diagnostics.getDiagnostics()) {
    System.out.println(d.getKind());
    System.out.println(d.getMessage(null));
}

可获取:

  • 错误 / 警告 / 提示
  • 行号、列号
  • 源文件
  • 错误码

这使得 IDE、代码分析器、在线判题系统 成为可能。


四、最小可运行示例

1. 编译磁盘上的 Java 文件

java 复制代码
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();

StandardJavaFileManager fileManager =
        compiler.getStandardFileManager(diagnostics, null, null);

Iterable<? extends JavaFileObject> units =
        fileManager.getJavaFileObjectsFromStrings(
                List.of("HelloWorld.java"));

boolean success = compiler.getTask(
        null,
        fileManager,
        diagnostics,
        null,
        null,
        units
).call();

2. 内存编译(无文件系统)

核心思路:

  • 自定义 SimpleJavaFileObject
  • String 存源码
  • ByteArrayOutputStream.class

这是 脚本引擎 / DSL / 规则引擎 的基础能力。


五、与 Annotation Processing(JSR 269)的关系

Java Compiler API 与 注解处理器 深度集成:

text 复制代码
javac
 ├─ Parse
 ├─ Enter
 ├─ Annotation Processing  ← APT
 ├─ Attr
 ├─ Flow
 ├─ Desugar
 └─ Generate

典型应用

  • Lombok
  • MapStruct
  • AutoValue
  • Dagger
  • 自研代码生成器

你可以通过 Compiler API 显式启用 / 控制注解处理器


六、典型应用场景

1. 代码分析 / 静态检查

  • 自研 Sonar 规则引擎
  • 编译级 AST 校验
  • API 兼容性检查

2. 动态代码执行

  • 在线判题系统
  • 规则引擎
  • 表达式语言(EL / DSL)

3. 插件系统

  • 热加载业务逻辑
  • 用户自定义扩展
  • 脚本替代 Groovy / JS

4. IDE / 工具链

  • 语法检查
  • 实时错误提示
  • 编译日志可视化

七、与 Roslyn(C#)的对比

维度 Java Compiler API Roslyn
AST 可操作性 中等 极强
API 现代性 一般 非常好
编译即服务 支持 原生支持
增量编译
语法树改写 困难 一等公民

Java Compiler API 偏"编译控制"

Roslyn 偏"编译平台"


八、局限性与注意事项

  1. 不是官方 Script Engine
  2. API 偏底层,使用成本高
  3. AST 操作不如 Roslyn 直观
  4. 模块化(JPMS)后 classpath 配置更复杂
  5. 不适合频繁高并发动态编译(需缓存 ClassLoader)

九、总结一句话

Java Compiler API 是"把 javac 变成库"的官方标准方案,是构建 Java 代码分析、动态编译、DSL、工具链与平台级能力的基础设施。

相关推荐
码兄科技13 分钟前
Java AI智能体开发实战:从零构建智能对话系统指南
java·开发语言·人工智能
折哥的程序人生 · 物流技术专研1 小时前
第8篇:六大设计原则在工厂模式中的体现
java·设计模式·设计原则·工厂模式·编程进阶·扩充系列
小明bishe181 小时前
计算机毕业设计之基于JAVA的植物科普网站
java·spring boot·spring·架构·课程设计
Drone_xjw1 小时前
从 GDB 到 CDB:C/C++ 程序调试的两把“手术刀”
c语言·开发语言·c++
r_oo_ki_e_1 小时前
Java Map 集合学习笔记
java·笔记·学习
SL-staff2 小时前
智慧园区2000+设备统一管理:JVS-IoT如何降低运维成本40%
java·开发语言·物联网·智慧园区·设备管理·运维优化·jvs-iot
咖啡八杯2 小时前
GoF设计模式——模板方法模式
java·后端·spring·设计模式
爱笑的源码基地3 小时前
一款全开源的信创云PACS影像云平台解决方案,支持多模态医学影像处理(CT/MR/DR/超声/病理等)
java·源码·国产化·pacs·云影像·区域pacs
我命由我123453 小时前
Android 开发问题:ClickableSpan 的点击事件没有生效
java·java-ee·android studio·android jetpack·android-studio·android runtime
2zcode4 小时前
基于MATLAB图像处理的饮料瓶灌装液位检测系统设计与实现
开发语言·图像处理·matlab