package org.example.demo.util;
import javax.tools.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 类编译器
*
* @author moon
* @date 2023-02-15 20:09
* @since 1.8
*/
public class CustomClassCompiler {
private JavaCompiler javac;
private CustomClassLoader classLoader;
private Iterable<String> options;
boolean ignoreWarnings = false;
/**
* 缓存待编译的源码
*/
private Map<String, CustomSourceCode> sourceCodes = new ConcurrentHashMap<>(16);
/**
* 缓存生成的类
*/
private Map<String, Class<?>> classMap = new ConcurrentHashMap<>(16);
/**
* 单例编译器
*/
private static volatile CustomClassCompiler compiler;
/**
* 获取实例
* @return
*/
public static CustomClassCompiler newInstance(ClassLoader parent) {
if ( null==compiler ){
synchronized (CustomClassCompiler.class){
if (null==compiler){
compiler = new CustomClassCompiler();
if (null!=parent){
compiler.useParentClassLoader(parent);
}
}
}
}
return compiler;
}
/**
* 默认类加载器 (私有化构造)
*/
private CustomClassCompiler() {
this.javac = ToolProvider.getSystemJavaCompiler();
this.classLoader = new CustomClassLoader(ClassLoader.getSystemClassLoader());
}
/**
* 使用父类加载器
* @param parent
* @return
*/
private CustomClassCompiler useParentClassLoader(ClassLoader parent) {
this.classLoader = new CustomClassLoader(parent);
return this;
}
/**
* @return the class loader used internally by the compiler
*/
public ClassLoader getClassloader() {
return classLoader;
}
/**
* Options used by the compiler, e.g. '-Xlint:unchecked'.
*
* @param options
* @return
*/
public void useOptions(String... options) {
this.options = Arrays.asList(options);
}
/**
* 忽略警告信息
*/
public void ignoreWarnings() {
ignoreWarnings = true;
}
/**
* 向编译器添加源码
* @param className
* @param sourceCode
* @return
* @throws Exception
*/
public CustomClassCompiler addSource(String className, String sourceCode) {
sourceCodes.put(className, new CustomSourceCode(className, sourceCode));
return this;
}
/**
* 编译源码
*
* @param classNames
* @return
*/
public boolean compile(String ... classNames) {
try {
compileByNames(Arrays.asList(classNames));
return true;
} catch (Exception e) {
System.out.println("Compile Exception:" + e.getMessage());
return false;
}
}
/**
* 获取类
* @param className
* @return
*/
public Class<?> getClassByName(String className){
return classMap.get(className);
}
/**
* 编译源码
*
* @return Map containing instances of all compiled classes
* @throws Exception
*/
private void compileByNames(List<String> classNames) throws Exception {
if (sourceCodes.size() == 0) {
throw new RuntimeException("No source code to compile");
}
//获取待编译类源码
Collection<CustomSourceCode> compilationUnits;
Set<String> keyTemp = null;
if (null != classNames && classNames.size() > 0){
compilationUnits = new ArrayList<>(classNames.size());
keyTemp = new HashSet<>(classNames.size());
for (String key:classNames){
if (sourceCodes.containsKey(key)){
keyTemp.add(key);
compilationUnits.add(sourceCodes.get(key));
}
}
} else {
keyTemp = sourceCodes.keySet();
compilationUnits = sourceCodes.values();
}
//检测源码是否全部存在
if (keyTemp.size() < classNames.size()){
throw new RuntimeException("Some source code not exist");
}
//定义警告和错误信息输出集合
DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
CustomJavaFileManager fileManager = new CustomJavaFileManager(javac.getStandardFileManager(null, null, StandardCharsets.UTF_8), classLoader);
JavaCompiler.CompilationTask task = javac.getTask(null, fileManager, collector, options, null, compilationUnits);
//编译
boolean result = task.call();
//编译结果
if (!result || collector.getDiagnostics().size() > 0) {
StringBuffer exceptionMsg = new StringBuffer();
exceptionMsg.append("Unable to compile the source");
boolean hasWarnings = false;
boolean hasErrors = false;
for (Diagnostic<? extends JavaFileObject> d : collector.getDiagnostics()) {
switch (d.getKind()) {
case NOTE:
case MANDATORY_WARNING:
case WARNING:
hasWarnings = true;
break;
case OTHER:
case ERROR:
hasErrors = true;
break;
default:
break;
}
exceptionMsg.append("\n").append("[kind=").append(d.getKind());
exceptionMsg.append(", ").append("line=").append(d.getLineNumber());
exceptionMsg.append(", ").append("message=").append(d.getMessage(Locale.US)).append("]");
}
//是否忽略警告
if ((hasWarnings && !ignoreWarnings ) || hasErrors) {
throw new RuntimeException(exceptionMsg.toString());
}
}
//遍历并缓存编译后的源码
for (String className : keyTemp) {
classMap.put(className, classLoader.loadClass(className));
}
}
}
没有合适的资源?快使用搜索试试~ 我知道了~
Jdk 动态编译 Java 源码测试 Demo
共9个文件
java:8个
xml:1个
需积分: 14 1 下载量 51 浏览量
2023-02-15
22:51:51
上传
评论
收藏 10KB ZIP 举报
温馨提示
Jdk 动态编译 Java 源码测试 Demo 通过 Jdk 工具类,直接将 Java 源码编译为 Class 字节码,并可加载为 Class 对象; 实例化后,可调用实例对象的方法 通过上面的实现,可以在线动态修改源码,并触发编译,加载到线上项目内,实现类似于热 部署的效果
资源推荐
资源详情
资源评论
收起资源包目录
DynamicDemo.zip (9个子文件)
DynamicDemo
pom.xml 652B
src
test
java
main
resources
java
org
example
demo
handler
BaseHandler.java 234B
App.java 4KB
common
UserSortOthers.java 814B
util
CustomSourceCode.java 1KB
CustomJavaFileObject.java 1KB
CustomJavaFileManager.java 1KB
CustomClassCompiler.java 6KB
CustomClassLoader.java 1KB
共 9 条
- 1
资源评论
猪悟道
- 粉丝: 8312
- 资源: 27
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功