diff --git a/README.md b/README.md index 693c9d1e7c92935831fdc69215fb538cb2737b1a..92b95eedb79bb8cbad1a4352fc24c46fef14eb99 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ com.gitee.wb04307201 loader-util - 1.1.1 + 1.1.2 ``` diff --git a/src/main/java/cn/wubo/loader/util/class_loader/DynamicClass.java b/src/main/java/cn/wubo/loader/util/class_loader/DynamicClass.java index 26694550174133361377e79540adc3cc00c8be4f..e8d049d0a53e5177137ec94ecc28bca20c1a759b 100644 --- a/src/main/java/cn/wubo/loader/util/class_loader/DynamicClass.java +++ b/src/main/java/cn/wubo/loader/util/class_loader/DynamicClass.java @@ -8,6 +8,7 @@ import javax.tools.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -19,7 +20,7 @@ public class DynamicClass { @Getter private String fullClassName; private List options = new ArrayList<>(); - private byte[] classData; + private MemFileManager fileManager; public DynamicClass(String javaSourceCode, String fullClassName) { this.javaSourceCode = javaSourceCode; @@ -28,8 +29,9 @@ public class DynamicClass { /** * 初始化一个DynamicClass对象 + * * @param javaSourceCode Java源代码字符串 - * @param fullClassName 完整的类名 + * @param fullClassName 完整的类名 * @return 初始化后的DynamicClass对象 */ public static DynamicClass init(String javaSourceCode, String fullClassName) { @@ -140,9 +142,8 @@ public class DynamicClass { return this; } - /** - * 编译方法 + * 编译Java代码 * * @return 返回DynamicClass对象 */ @@ -156,7 +157,7 @@ public class DynamicClass { DiagnosticCollector diagnosticCollector = new DiagnosticCollector<>(); // 创建内存文件管理器 - MemFileManager fileManager = new MemFileManager(compiler.getStandardFileManager(diagnosticCollector, null, null)); + this.fileManager = new MemFileManager(compiler.getStandardFileManager(diagnosticCollector, null, null)); // 创建JavaMemSource对象 JavaMemSource file = new JavaMemSource(fullClassName, javaSourceCode); @@ -169,22 +170,17 @@ public class DynamicClass { JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnosticCollector, options, null, compilationUnits); log.debug("执行编译"); + boolean result = task.call(); // 执行编译任务 - if (Boolean.TRUE.equals(task.call())) { - log.debug("编译成功"); - // 如果编译成功,将生成的Java类数据保存到classData变量中 - classData = fileManager.getJavaMemClass().getBytes(); - } else { - StringBuilder message = new StringBuilder(); - // 遍历诊断收集器中的诊断信息,将错误信息添加到message中 - for (Diagnostic diagnostics : diagnosticCollector.getDiagnostics()) { - message.append("\r\n").append(diagnostics.toString()); - } - log.debug("编译失败 {}", message); - // 如果编译失败,抛出LoaderRuntimeException异常,并传递错误信息 - throw new LoaderRuntimeException(message.toString()); + if (!result) { + // 处理编译错误 + String errorMessage = diagnosticCollector.getDiagnostics().stream() + .map(Object::toString) + .reduce("", (acc, x) -> acc + "\r\n" + x); + log.debug("编译失败: {}", errorMessage); + throw new LoaderRuntimeException("编译失败: " + errorMessage); } - // 返回DynamicClass对象 + log.debug("编译成功"); return this; } @@ -198,13 +194,17 @@ public class DynamicClass { */ public Class load() { try { - // 创建一个动态类加载器 - DynamicClassLoader myClassLoader = new DynamicClassLoader(classData); - // 使用加载器加载指定的类 - return myClassLoader.loadClass(fullClassName); + // 获取已编译的类数据 + Map compiledClasses = fileManager.getAllCompiledClassesData(); + // 创建动态类加载器 + DynamicClassLoader classLoader = new DynamicClassLoader(Thread.currentThread().getContextClassLoader()); + // 将已编译的类数据添加到动态类加载器中 + compiledClasses.forEach(classLoader::addClass); + // 加载指定类的类对象 + return classLoader.loadClass(fullClassName); } catch (ClassNotFoundException e) { - // 如果找不到指定的类,则抛出运行时异常 - throw new LoaderRuntimeException(e.getMessage(), e); + // 加载类失败,抛出LoaderRuntimeException异常 + throw new LoaderRuntimeException("加载类失败: " + e.getMessage(), e); } } diff --git a/src/main/java/cn/wubo/loader/util/class_loader/DynamicClassLoader.java b/src/main/java/cn/wubo/loader/util/class_loader/DynamicClassLoader.java index 82bc6f2c727fa4c0c107868b26c78a852a28199d..68b667e93cde5e6c284b8622c77cb72280570cae 100644 --- a/src/main/java/cn/wubo/loader/util/class_loader/DynamicClassLoader.java +++ b/src/main/java/cn/wubo/loader/util/class_loader/DynamicClassLoader.java @@ -1,6 +1,8 @@ package cn.wubo.loader.util.class_loader; import java.security.SecureClassLoader; +import java.util.HashMap; +import java.util.Map; /** * @description:动态编译加载器 @@ -10,25 +12,34 @@ import java.security.SecureClassLoader; public class DynamicClassLoader extends SecureClassLoader { /** - * 编译的时候返回的class字节数组 + * 编译的时候返回的class字节数组-支持内部类 */ - private byte[] classData; + private final Map classBytes = new HashMap<>(); - public DynamicClassLoader(byte[] classData) { - super(); - this.classData = classData; + public DynamicClassLoader(ClassLoader parent) { + super(parent); } + public void addClass(String fullClassName, byte[] classData) { + classBytes.put(fullClassName, classData); + } + + /** + * 重写父类方法,用于查找指定的类。 + * + * @param fullClassName 指定的类名 + * @return 查找到的类对象 + * @throws ClassNotFoundException 如果找不到指定的类,则抛出该异常 + */ @Override protected Class findClass(String fullClassName) throws ClassNotFoundException { - // 1. 判断编译的class字节数组为null,若为null则说明已经编译过,无需再编译 - if (classData == null || classData.length == 0) - throw new ClassNotFoundException("[动态编译]classdata不存在"); - // 2. 加载class字节数组 + // 获取指定类的字节码数据 + byte[] classData = classBytes.get(fullClassName); + if (classData == null) { + // 如果找不到指定的类,则抛出ClassNotFoundException异常 + throw new ClassNotFoundException("[动态编译]找不到类: " + fullClassName); + } + // 定义并返回指定的类对象 return defineClass(fullClassName, classData, 0, classData.length); } - - - - } diff --git a/src/main/java/cn/wubo/loader/util/class_loader/MemFileManager.java b/src/main/java/cn/wubo/loader/util/class_loader/MemFileManager.java index 7c663b3b8f5efc03e3bdc4f54e398ddb1641534f..2ad832d276b064db59ef354325c96b3e2885a9ef 100644 --- a/src/main/java/cn/wubo/loader/util/class_loader/MemFileManager.java +++ b/src/main/java/cn/wubo/loader/util/class_loader/MemFileManager.java @@ -4,6 +4,8 @@ import javax.tools.FileObject; import javax.tools.ForwardingJavaFileManager; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; +import java.util.HashMap; +import java.util.Map; /** * @description: 内存文件管理器 @@ -12,32 +14,41 @@ import javax.tools.JavaFileObject; */ public class MemFileManager extends ForwardingJavaFileManager { - /** - * class内存对象 - */ - private JavaMemClass javaMemClass; + private final Map compiledClasses = new HashMap<>(); - protected MemFileManager(JavaFileManager fileManager) { - super(fileManager); - } - - public JavaMemClass getJavaMemClass() { - return javaMemClass; - } - - /** - * 根据给定参数获取用于输出Java代码的JavaFileObject对象。 - * - * @param location 代码发生的位置 - * @param className 类名 - * @param kind Java文件对象的类型 - * @param sibling 与新创建的JavaFileObject具有相同父级文件对象的兄弟文件对象 - * @return 用于输出Java代码的JavaFileObject对象 - */ - @Override - public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) { - javaMemClass = new JavaMemClass(className, kind); - return javaMemClass; - } + protected MemFileManager(JavaFileManager fileManager) { + super(fileManager); + } + /** + * 根据给定参数获取用于输出Java代码的JavaFileObject对象。 + * + * @param location 代码发生的位置 + * @param className 类名 + * @param kind Java文件对象的类型 + * @param sibling 与新创建的JavaFileObject具有相同父级文件对象的兄弟文件对象 + * @return 用于输出Java代码的JavaFileObject对象 + */ + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) { + // 这里创建的JavaMemClass实例会被JavaCompiler用来存储编译好的类的字节码数据 + JavaMemClass javaMemClass = new JavaMemClass(className, kind); + // 存储编译好的类 + compiledClasses.put(className, javaMemClass); + return javaMemClass; + } + + /** + * 获取所有编译好的类的字节码数据 + * + * @return 所有编译好的类的字节码数据的Map,键为类名,值为类的字节码数据 + */ + public Map getAllCompiledClassesData() { + Map classDataMap = new HashMap<>(); + for (Map.Entry entry : compiledClasses.entrySet()) { + // 将每个编译好的类的字节码数据存入Map中 + classDataMap.put(entry.getKey(), entry.getValue().getBytes()); + } + return classDataMap; + } }