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、工具链与平台级能力的基础设施。

相关推荐
小法师爱分享1 分钟前
StickyNotes,简单便签超实用
java·python
qq_297574672 分钟前
Linux 服务器 Java 开发环境搭建保姆级教程
java·linux·服务器
金牌归来发现妻女流落街头14 分钟前
【从SpringBoot到SpringCloud】
java·spring boot·spring cloud
毅炼14 分钟前
Java 基础常见问题总结(4)
java·后端
无小道16 分钟前
Qt——事件简单介绍
开发语言·前端·qt
devmoon21 分钟前
在 Paseo 测试网上获取 Coretime:On-demand 与 Bulk 的完整实操指南
开发语言·web3·区块链·测试用例·智能合约·solidity
GR23423426 分钟前
2025年影视仓TV+手机官方版 内置地址源支持高清直播
java·智能手机·软件
kylezhao201938 分钟前
C# 中的 SOLID 五大设计原则
开发语言·c#
程序员清风1 小时前
北京回长沙了,简单谈谈感受!
java·后端·面试
何中应1 小时前
请求头设置没有生效
java·后端