源码编译工具 - CompilerUtil
# 源码编译工具 - CompilerUtil
简介
CompilerUtil
是 Hutool 提供的一个用于动态编译 Java 源码的工具类。JDK 中自带的 JavaCompiler
可以实现动态编译,从而让 Java 具备动态脚本的特性。CompilerUtil
对此进行了封装,简化了源码的编译过程,使得在运行时编译并加载 Java 源码更加方便。
# 1. 使用场景
- 动态脚本执行:在需要运行时编译和执行 Java 代码的场景下,可以使用
CompilerUtil
进行动态编译并加载执行。 - 编译器扩展:在开发 IDE 或代码分析工具时,可以利用
CompilerUtil
编译用户输入的代码并立即运行或测试。 - 代码热替换:在服务端或应用程序中,需要在不重启的情况下动态更新某些类的实现时,可以使用
CompilerUtil
进行代码热替换。
# 2. 主要方法与示例
# 2.1 getCompiler
- 获取编译器实例
getCompiler
方法用于获取 JavaCompiler
实例,可以通过传入参数自定义输出错误信息的处理方式。
# 示例:获取编译器并添加源码
import cn.hutool.core.compiler.CompilerUtil;
import javax.tools.JavaCompiler;
public class CompilerUtilExample {
public static void main(String[] args) {
// 获取默认的JavaCompiler实例
JavaCompiler compiler = CompilerUtil.getCompiler(null);
// 添加源码文件进行编译
compiler.addSource(FileUtil.file("path/to/YourSource.java"));
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 方法签名:
public static JavaCompiler getCompiler(DiagnosticListener<? super JavaFileObject> diagnosticListener)
- 参数说明:
diagnosticListener
:用于处理编译器错误、警告等信息的监听器。传入null
则使用默认处理方式。
- 作用:获取
JavaCompiler
实例并进行自定义设置,适用于需要动态编译源码的场景。
# 2.2 addSource
- 添加待编译的源码文件或源码字符串
该方法用于添加待编译的源码,可以是文件形式,也可以是字符串形式的源码内容。
# 示例:添加源码文件和源码字符串
import cn.hutool.core.compiler.CompilerUtil;
public class CompilerUtilExample {
public static void main(String[] args) {
// 获取编译器实例
JavaCompiler compiler = CompilerUtil.getCompiler(null);
// 添加源码文件进行编译
compiler.addSource(FileUtil.file("path/to/YourSource.java"));
// 添加源码字符串进行编译
String sourceCode = "public class YourClass { public void sayHello() { System.out.println(\"Hello, World!\"); } }";
compiler.addSource("YourClass", sourceCode);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 方法签名:
public JavaCompiler addSource(File file)
public JavaCompiler addSource(String className, String source)
- 参数说明:
file
:待编译的源码文件。className
:类名,用于标识源码字符串。source
:源码字符串内容。
- 作用:用于添加需要编译的源码文件或源码字符串,适用于在运行时动态添加代码的场景。
# 2.3 addLibrary
- 添加编译依赖的库
该方法用于在编译时添加依赖的库,可以是包含 .class
文件的 jar 包。
# 示例:添加依赖库进行编译
import cn.hutool.core.compiler.CompilerUtil;
public class CompilerUtilExample {
public static void main(String[] args) {
// 获取编译器实例
JavaCompiler compiler = CompilerUtil.getCompiler(null);
// 添加源码文件
compiler.addSource(FileUtil.file("path/to/YourSource.java"));
// 添加依赖库(jar 包或 .class 文件)
File libFile = FileUtil.file("path/to/yourLibrary.jar");
compiler.addLibrary(libFile);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 方法签名:
public JavaCompiler addLibrary(File file)
- 参数说明:
file
:编译所依赖的库,可以是 jar 包或 .class 文件的压缩包。
- 作用:在动态编译过程中添加外部依赖库,适用于需要编译时依赖特定库的场景。
# 2.4 compile
- 执行编译并返回类加载器
该方法用于执行编译操作,并返回包含编译结果的类加载器。
# 示例:编译源码并加载类
import cn.hutool.core.compiler.CompilerUtil;
import cn.hutool.core.util.ReflectUtil;
public class CompilerUtilExample {
public static void main(String[] args) throws ClassNotFoundException {
// 获取编译器实例
JavaCompiler compiler = CompilerUtil.getCompiler(null);
// 添加源码文件
compiler.addSource(FileUtil.file("path/to/YourSource.java"));
// 执行编译并获取类加载器
ClassLoader classLoader = compiler.compile();
// 加载编译后的类并创建实例
Class<?> clazz = classLoader.loadClass("YourClass");
Object obj = ReflectUtil.newInstance(clazz);
// 调用方法
ReflectUtil.invoke(obj, "sayHello"); // 输出: Hello, World!
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 方法签名:
public ClassLoader compile()
- 参数说明:无参数
- 作用:执行编译并返回包含编译结果的类加载器,适用于需要在运行时动态加载编译后的类并执行的场景。
# 3. 实际应用场景
- 动态代码执行:在需要动态编写和执行代码的场景,如脚本执行、规则引擎等,可以利用
CompilerUtil
实现即时编译与执行。 - 插件机制:在开发需要动态加载和执行用户自定义逻辑的应用程序时,可以通过
CompilerUtil
动态编译和加载这些逻辑模块。 - 编译时自定义处理:在编写开发工具时,可能需要对用户输入的代码进行即时编译并反馈结果,
CompilerUtil
提供了灵活的方式来实现这一需求。
# 4. 注意事项
- 编译时需要确保所有依赖库已正确加载,避免出现
ClassNotFoundException
。 - 在生产环境中使用动态编译时需注意性能开销和安全性,建议进行充分的测试与验证。
编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08