From ee334b4cd568785530aadab7ef14e0b9b0e140e4 Mon Sep 17 00:00:00 2001 From: wangyu <727842003@qq.com> Date: Fri, 15 Jan 2021 11:33:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9classloader?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/compiler/core/ClassLoaders.java | 15 +++ .../compiler/core/JavaStringCompiler.java | 109 ++++++++---------- .../compiler/core/MemoryClassLoader.java | 33 +++--- .../compiler/core/MemoryJavaFileManager.java | 5 +- .../support/DelegateJavaCompiler.java | 21 ++-- .../framework/boot/FlyfishAppRunner.java | 3 +- 6 files changed, 97 insertions(+), 89 deletions(-) create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/compiler/core/ClassLoaders.java diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/ClassLoaders.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/ClassLoaders.java new file mode 100644 index 0000000..0a4a86b --- /dev/null +++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/ClassLoaders.java @@ -0,0 +1,15 @@ +package com.flyfish.framework.compiler.core; + +/** + * 静态访问器 + * + * @author wangyu + */ +public interface ClassLoaders { + + MemoryClassLoader CLASS_LOADER = new MemoryClassLoader(); + + static MemoryClassLoader memory() { + return CLASS_LOADER; + } +} diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/JavaStringCompiler.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/JavaStringCompiler.java index 5ca66ec..10bed67 100644 --- a/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/JavaStringCompiler.java +++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/JavaStringCompiler.java @@ -16,67 +16,58 @@ import java.util.Map; */ public class JavaStringCompiler implements Closeable { - private final JavaCompiler compiler; - private final MemoryJavaFileManager manager; - private final MemoryClassLoader classLoader; + private final JavaCompiler compiler; + private final MemoryJavaFileManager manager; + private final MemoryClassLoader classLoader; - public JavaStringCompiler() { - this.compiler = ToolProvider.getSystemJavaCompiler(); - StandardJavaFileManager stdManager = compiler.getStandardFileManager(null, null, null); - this.manager = new MemoryJavaFileManager(stdManager); - this.classLoader = new MemoryClassLoader(manager.getClassBytes()); - } + public JavaStringCompiler(MemoryClassLoader classLoader) { + this.compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager stdManager = compiler.getStandardFileManager(null, null, null); + this.manager = new MemoryJavaFileManager(stdManager, classLoader); + this.classLoader = classLoader; + } - /** - * Compile a Java source file in memory. - * - * @param fileName Java file name, e.g. "Test.java" - * @param source The source code as String. - * @return The compiled results as Map that contains class name as key, - * class binary as value. - * @throws IOException If compile error. - */ - public Map compile(String fileName, String source) { - JavaFileObject javaFileObject = manager.makeStringSource(fileName, source); - JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, Collections.singletonList(javaFileObject)); - Boolean result = task.call(); - if (result == null || !result) { - throw new RuntimeException("Compilation failed."); - } - return manager.getClassBytes(); - } + /** + * Compile a Java source file in memory. + * + * @param fileName Java file name, e.g. "Test.java" + * @param source The source code as String. + * @return The compiled results as Map that contains class name as key, + * class binary as value. + * @throws IOException If compile error. + */ + public Map compile(String fileName, String source) { + JavaFileObject javaFileObject = manager.makeStringSource(fileName, source); + JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, Collections.singletonList(javaFileObject)); + Boolean result = task.call(); + if (result == null || !result) { + throw new RuntimeException("Compilation failed."); + } + return manager.getClassBytes(); + } - /** - * Load class from compiled classes. - * - * @param name Full class name. - * @return The Class instance. - * @throws ClassNotFoundException If class not found. - */ - public Class loadClass(String name) throws ClassNotFoundException { - return classLoader.loadClass(name); - } + /** + * Load class from compiled classes. + * + * @param name Full class name. + * @return The Class instance. + * @throws ClassNotFoundException If class not found. + */ + public Class loadClass(String name) throws ClassNotFoundException { + return classLoader.loadClass(name); + } - /** - * get the classLoader - * - * @return 结果 - */ - public ClassLoader getClassLoader() { - return classLoader; - } - - @Override - public void close() { - try { - if (null != manager) { - manager.close(); - } - if (null != classLoader) { - classLoader.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } + @Override + public void close() { + try { + if (null != manager) { + manager.close(); + } + if (null != classLoader) { + classLoader.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/MemoryClassLoader.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/MemoryClassLoader.java index 06eea9a..703ad6f 100644 --- a/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/MemoryClassLoader.java +++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/MemoryClassLoader.java @@ -3,6 +3,7 @@ package com.flyfish.framework.compiler.core; import java.net.URL; import java.net.URLClassLoader; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * Load class from byte[] which is compiled in memory. @@ -11,22 +12,24 @@ import java.util.Map; */ class MemoryClassLoader extends URLClassLoader { - // class name to class bytes: - private final Map classBytes; + // class name to class bytes: + private final Map classBytes = new ConcurrentHashMap<>(); - public MemoryClassLoader(Map classBytes) { - super(new URL[0], MemoryClassLoader.class.getClassLoader()); - this.classBytes = classBytes; - } + public MemoryClassLoader() { + super(new URL[0], MemoryClassLoader.class.getClassLoader()); + } - @Override - protected Class findClass(String name) throws ClassNotFoundException { - byte[] buf = classBytes.get(name); - if (buf == null) { - return super.findClass(name); - } - classBytes.remove(name); - return defineClass(name, buf, 0, buf.length); - } + @Override + protected Class findClass(String name) throws ClassNotFoundException { + byte[] buf = classBytes.get(name); + if (buf == null) { + return super.findClass(name); + } + classBytes.remove(name); + return defineClass(name, buf, 0, buf.length); + } + public Map getClassBytes() { + return classBytes; + } } diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/MemoryJavaFileManager.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/MemoryJavaFileManager.java index bf6bab4..269fcb0 100644 --- a/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/MemoryJavaFileManager.java +++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/core/MemoryJavaFileManager.java @@ -19,10 +19,11 @@ import java.util.concurrent.ConcurrentHashMap; class MemoryJavaFileManager extends ForwardingJavaFileManager { // compiled classes in bytes: - final Map classBytes = new ConcurrentHashMap<>(); + private final Map classBytes; - MemoryJavaFileManager(JavaFileManager fileManager) { + MemoryJavaFileManager(JavaFileManager fileManager, MemoryClassLoader classLoader) { super(fileManager); + classBytes = classLoader.getClassBytes(); } public Map getClassBytes() { diff --git a/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/DelegateJavaCompiler.java b/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/DelegateJavaCompiler.java index 7eb6ccb..3a978e7 100644 --- a/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/DelegateJavaCompiler.java +++ b/flyfish-common/src/main/java/com/flyfish/framework/compiler/support/DelegateJavaCompiler.java @@ -1,12 +1,10 @@ package com.flyfish.framework.compiler.support; import com.flyfish.framework.compiler.DynamicJavaCompiler; +import com.flyfish.framework.compiler.core.ClassLoaders; import com.flyfish.framework.compiler.core.JavaStringCompiler; import org.apache.commons.lang3.StringUtils; -import org.springframework.util.StreamUtils; -import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.Map; /** @@ -17,7 +15,7 @@ import java.util.Map; public class DelegateJavaCompiler implements DynamicJavaCompiler { // 第三方编译器 - private final JavaStringCompiler compiler = new JavaStringCompiler(); + private final JavaStringCompiler compiler = new JavaStringCompiler(ClassLoaders.memory()); private DelegateJavaCompiler() { } @@ -27,7 +25,7 @@ public class DelegateJavaCompiler implements DynamicJavaCompiler { } public static ClassLoader classLoader() { - return getInstance().compiler.getClassLoader(); + return ClassLoaders.memory(); } /** @@ -54,17 +52,16 @@ public class DelegateJavaCompiler implements DynamicJavaCompiler { compiler.close(); } - private static class SingletonHolder { private static final DelegateJavaCompiler INSTANCE = new DelegateJavaCompiler(); } - public static void main(String[] args) throws ClassNotFoundException, IOException { - long time = System.currentTimeMillis(); - System.out.println(StreamUtils.copyToString(DelegateJavaCompiler.class.getResourceAsStream("./"), StandardCharsets.UTF_8)); - Class clazz = getInstance().compile("Fuck.java", "package com.flyfish.project; public class Fuck {}"); - System.out.println(clazz + "耗时:" + (System.currentTimeMillis() - time) / 1000.0 + "秒"); - } +// public static void main(String[] args) throws ClassNotFoundException, IOException { +// long time = System.currentTimeMillis(); +// System.out.println(StreamUtils.copyToString(DelegateJavaCompiler.class.getResourceAsStream("./"), StandardCharsets.UTF_8)); +// Class clazz = getInstance().compile("Fuck.java", "package com.flyfish.project; public class Fuck {}"); +// System.out.println(clazz + "耗时:" + (System.currentTimeMillis() - time) / 1000.0 + "秒"); +// } } diff --git a/flyfish-web/src/main/java/com/flyfish/framework/boot/FlyfishAppRunner.java b/flyfish-web/src/main/java/com/flyfish/framework/boot/FlyfishAppRunner.java index 9a4722f..1d54e85 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/boot/FlyfishAppRunner.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/boot/FlyfishAppRunner.java @@ -1,6 +1,7 @@ package com.flyfish.framework.boot; +import com.flyfish.framework.compiler.core.ClassLoaders; import com.flyfish.framework.compiler.support.DelegateJavaCompiler; import org.springframework.boot.SpringApplication; import org.springframework.context.ConfigurableApplicationContext; @@ -14,7 +15,7 @@ import org.springframework.context.ConfigurableApplicationContext; public class FlyfishAppRunner { public static ConfigurableApplicationContext run(Class primarySource, String... args) { - Thread.currentThread().setContextClassLoader(DelegateJavaCompiler.classLoader()); + Thread.currentThread().setContextClassLoader(ClassLoaders.memory()); return SpringApplication.run(new Class[]{primarySource}, args); }