From 61759104732f44eee6e17097b192ddc75ee457fe Mon Sep 17 00:00:00 2001 From: dh-free Date: Wed, 21 Feb 2024 10:45:21 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=89=A9=E5=B1=95=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E8=83=BD=E5=A4=9F=E5=A4=84=E7=90=86=E5=92=8C=E6=94=B6=E9=9B=86?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E5=90=8E=E7=9A=84=E6=89=80=E6=9C=89=E7=B1=BB?= =?UTF-8?q?=EF=BC=88=E5=8C=85=E6=8B=AC=E5=86=85=E9=83=A8=E7=B1=BB=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/class_loader/DynamicClass.java | 43 ++++++------- .../util/class_loader/DynamicClassLoader.java | 27 ++++---- .../util/class_loader/MemFileManager.java | 63 +++++++++++-------- 3 files changed, 70 insertions(+), 63 deletions(-) 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 2669455..c1c2442 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) { @@ -156,7 +158,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,27 +171,21 @@ 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,12 @@ 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); + 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 82bc6f2..b47400c 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,24 @@ 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); } @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) { + 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 7c663b3..a992468 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 + */ + public Map getAllCompiledClassesData() { + Map classDataMap = new HashMap<>(); + for (Map.Entry entry : compiledClasses.entrySet()) { + // 将每个编译好的类的字节码数据存入Map中 + classDataMap.put(entry.getKey(), entry.getValue().getBytes()); + } + return classDataMap; + } } -- Gitee From 1ba7dd07962d15b0e773ad02e8ceea2432480bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=8D=9A?= Date: Wed, 21 Feb 2024 12:12:06 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/wubo/loader/util/class_loader/DynamicClass.java | 9 +++++++-- .../loader/util/class_loader/DynamicClassLoader.java | 10 ++++++++++ .../wubo/loader/util/class_loader/MemFileManager.java | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) 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 c1c2442..e8d049d 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 @@ -142,9 +142,8 @@ public class DynamicClass { return this; } - /** - * 编译方法 + * 编译Java代码 * * @return 返回DynamicClass对象 */ @@ -186,6 +185,7 @@ public class DynamicClass { } + /** * 加载指定类的类对象。 * @@ -194,11 +194,16 @@ public class DynamicClass { */ public Class load() { try { + // 获取已编译的类数据 Map compiledClasses = fileManager.getAllCompiledClassesData(); + // 创建动态类加载器 DynamicClassLoader classLoader = new DynamicClassLoader(Thread.currentThread().getContextClassLoader()); + // 将已编译的类数据添加到动态类加载器中 compiledClasses.forEach(classLoader::addClass); + // 加载指定类的类对象 return classLoader.loadClass(fullClassName); } catch (ClassNotFoundException 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 b47400c..68b667e 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 @@ -24,12 +24,22 @@ public class DynamicClassLoader extends SecureClassLoader { classBytes.put(fullClassName, classData); } + /** + * 重写父类方法,用于查找指定的类。 + * + * @param fullClassName 指定的类名 + * @return 查找到的类对象 + * @throws ClassNotFoundException 如果找不到指定的类,则抛出该异常 + */ @Override protected Class findClass(String fullClassName) throws ClassNotFoundException { + // 获取指定类的字节码数据 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 a992468..2ad832d 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 @@ -41,7 +41,7 @@ public class MemFileManager extends ForwardingJavaFileManager { /** * 获取所有编译好的类的字节码数据 * - * @return + * @return 所有编译好的类的字节码数据的Map,键为类名,值为类的字节码数据 */ public Map getAllCompiledClassesData() { Map classDataMap = new HashMap<>(); -- Gitee From 8d6c2ae14ad3dfa96b655f3dba84330c4d833d21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=8D=9A?= Date: Wed, 21 Feb 2024 12:12:31 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 693c9d1..92b95ee 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ com.gitee.wb04307201 loader-util - 1.1.1 + 1.1.2 ``` -- Gitee