Java 動(dòng)態(tài)編譯在項(xiàng)目中的實(shí)踐分享
1、什么是動(dòng)態(tài)編譯
在 Java 中,動(dòng)態(tài)編譯是指在運(yùn)行時(shí)動(dòng)態(tài)地編譯 Java 源代碼,生成字節(jié)碼,并加載到 JVM 中執(zhí)行。動(dòng)態(tài)編譯可以用于實(shí)現(xiàn)動(dòng)態(tài)代碼生成、動(dòng)態(tài)加載、插件化等功能。
1.1、動(dòng)態(tài)編譯的相關(guān)概念
JavaFileManager 對(duì)象:用于管理編譯過程中的文件。
- JavaFileManager 是一個(gè)接口,提供了對(duì) Java 文件的管理功能,包括創(chuàng)建、查找、讀寫等操作。JavaFileManager 有多種實(shí)現(xiàn)方式,例如 StandardJavaFileManager、ForwardingJavaFileManager 等。
DiagnosticListener 對(duì)象:用于收集編譯時(shí)的診斷信息。
- DiagnosticListener 是一個(gè)接口,用于接收編譯時(shí)的診斷信息,例如錯(cuò)誤、警告等。
JavaFileObject 對(duì)象:表示要編譯的 Java 源代碼。
- JavaFileObject 是一個(gè)抽象類,用于表示 Java 源代碼或字節(jié)碼。JavaFileObject 有多種實(shí)現(xiàn)方式,例如 SimpleJavaFileObject、JavaFileObjectWrapper 等。
1.2、如何簡(jiǎn)單的實(shí)現(xiàn)動(dòng)態(tài)編譯
- 創(chuàng)建一個(gè) JavaCompiler 對(duì)象,該對(duì)象用于編譯 Java 源代碼。
- 創(chuàng)建一個(gè) DiagnosticCollector 對(duì)象,該對(duì)象用于收集編譯時(shí)的診斷信息。
- 創(chuàng)建一個(gè) JavaFileManager 對(duì)象,該對(duì)象用于管理編譯過程中的文件。
- 創(chuàng)建一個(gè) JavaFileObject 對(duì)象,該對(duì)象用于表示要編譯的 Java 源代碼。
- 調(diào)用 JavaCompiler 對(duì)象的 getTask 方法,傳入 JavaFileManager 對(duì)象和 DiagnosticCollector 對(duì)象,獲取一個(gè) CompilationTask 對(duì)象。
- 調(diào)用 CompilationTask 對(duì)象的 call 方法,編譯 Java 源代碼。
- 獲取 DiagnosticCollector 對(duì)象的診斷信息,并處理編譯結(jié)果。
下面是一個(gè)簡(jiǎn)單的示例,演示如何使用動(dòng)態(tài)編譯:
public class DynamicCompiler { ? ?public static void main(String[] args) throws Exception { ? ? ? ?// 創(chuàng)建 JavaCompiler 對(duì)象 ? ? ? ?JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); ? ? ? ?// 創(chuàng)建 DiagnosticCollector 對(duì)象,用于收集編譯時(shí)的診斷信息 ? ? ? ?DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); ? ? ? ?// 創(chuàng)建 JavaFileManager 對(duì)象,用于管理編譯過程中的文件 ? ? ? ?StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); ? ? ? ?// 創(chuàng)建 JavaFileObject 對(duì)象,用于表示要編譯的 Java 源代碼 ? ? ? ?String code = "public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } }"; ? ? ? ?JavaFileObject source = new JavaSourceFromString("HelloWorld", code); ? ? ? ?// 獲取 CompilationTask 對(duì)象 ? ? ? ?Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(source); ? ? ? ?CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits); ? ? ? ?// 編譯 Java 源代碼 ? ? ? ?boolean success = task.call(); ? ? ? ?// 獲取診斷信息 ? ? ? ?List<Diagnostic<? extends JavaFileObject>> messages = diagnostics.getDiagnostics(); ? ? ? ?for (Diagnostic<? extends JavaFileObject> message : messages) { ? ? ? ? ? ?System.out.println(message.getMessage(null)); ? ? ? } ? ? ? ?// 處理編譯結(jié)果 ? ? ? ?if (success) { ? ? ? ? ? ?System.out.println("Compilation was successful."); ? ? ? } else { ? ? ? ? ? ?System.out.println("Compilation failed."); ? ? ? } ? ? ? ?fileManager.close(); ? } } ? class JavaSourceFromString extends SimpleJavaFileObject { ? ?final String code; ? ? ?JavaSourceFromString(String name, String code) { ? ? ? ?super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); ? ? ? ?this.code = code; ? } ? ? ?@Override ? ?public CharSequence getCharContent(boolean ignoreEncodingErrors) { ? ? ? ?return code; ? } }
運(yùn)行結(jié)果:
Hello World!
Compilation was successful.
2、如何結(jié)合 springboot 項(xiàng)目使用
上面展示了如何簡(jiǎn)單使用 Java 的動(dòng)態(tài)編譯功能,但是在日常項(xiàng)目開發(fā)中,會(huì)面對(duì)更多的場(chǎng)景。結(jié)合前言中我所遇到的問題,我簡(jiǎn)單的給大家介紹下我在項(xiàng)目中是如何使用 Java 的動(dòng)態(tài)編譯功能來解決我所遇到的問題的。
我當(dāng)時(shí)的想法是這樣的:
這樣,各個(gè)業(yè)務(wù)方就可以自己管理自己的代碼塊,與外部對(duì)接或者修改代碼無需在發(fā)布應(yīng)用,徹底解放了我,讓我有更多的精力給公司做更重要的事情!
2.1、動(dòng)態(tài)編譯在項(xiàng)目中遇到的問題
2.1.1、必須重寫類加載器新編譯的代碼才能生效
在 Java 中使用動(dòng)態(tài)編譯功能時(shí),重寫類加載器是必要的。這是因?yàn)閯?dòng)態(tài)編譯生成的類需要加載到 JVM 中執(zhí)行,而默認(rèn)的類加載器無法加載動(dòng)態(tài)生成的類。
在 Java 中,類加載器分為三種:?jiǎn)?dòng)類加載器、擴(kuò)展類加載器和應(yīng)用程序類加載器。默認(rèn)情況下,Java 使用應(yīng)用程序類加載器來加載類。應(yīng)用程序類加載器只能加載預(yù)先編譯好的類,無法加載動(dòng)態(tài)生成的類。因此,我們需要重寫類加載器,使其能夠加載動(dòng)態(tài)生成的類。
重寫類加載器有兩種方式:繼承 ClassLoader 類或?qū)崿F(xiàn) ClassLoader 接口。一般情況下,我們建議使用繼承 ClassLoader 類的方式,因?yàn)檫@樣可以更方便地控制類加載的過程。
當(dāng)我們重寫類加載器時(shí),需要實(shí)現(xiàn) findClass 方法。findClass 方法用于查找指定名稱的類。如果類已經(jīng)被加載過,可以直接返回已加載的類;否則,需要使用動(dòng)態(tài)編譯生成類的字節(jié)碼,并通過 defineClass 方法將其加載到 JVM 中執(zhí)行。
2.1.2、沒有依賴的簡(jiǎn)單代碼可以編譯成功,但是一旦有依賴關(guān)系,編譯就會(huì)失敗
Java 編譯器是通過 JavaFileManager 來加載相關(guān)依賴類的,如果不重寫使用的是默認(rèn)的 JavaFileManager 來獲取 springboot 的 jarFile 來讀取嵌套 jar,自然是獲取不到的,需要我們重寫 JavaFileManager,去獲取編譯代碼所需的依賴,具體寫法詳見 2.2 代碼示例。
2.2、代碼示例
?// 通過調(diào)用這個(gè)方法即可實(shí)現(xiàn) java 的動(dòng)態(tài)編譯功能啦 public static Class compile(String className, String code) { ? ? ? ?try (MemoryClassLoader loader = MemoryClassLoader.genInstance()) { ? ? ? ? ? ?loader.registerJava(className, code); ? ? ? ? ? ?return MemoryClassLoader.getInstance().loadClass(className); ? ? ? } catch (Exception e) { ? ? ? ? ?// ignore ? ? ? } ? } }
public class MemoryClassLoader extends URLClassLoader { ? ? ?private static final Map<String, byte[]> classBytes = new ConcurrentHashMap<>(); ? ? ?private MemoryClassLoader() { ? ? ? ?super(new URL[0], MemoryClassLoader.class.getClassLoader()); ? } ? ? ?private static final Map<String, MemoryClassLoader> CLASSLOADER_MAP = new ConcurrentHashMap<String, MemoryClassLoader>() {{ ? ? ? ?put(KEY_CLASSLOADER, new MemoryClassLoader()); ? }}; ? ? ?private static final String KEY_CLASSLOADER = "key_classloader"; ? ? ?/** ? ? * 注冊(cè) Java 字符串到內(nèi)存類加載器中 ? ? */ ? ?public void registerJava(String className, String javaCode) { ? ? ? ?try { ? ? ? ? ? ?Map<String, byte[]> compile = compile(className, javaCode); ? ? ? ? ? ?if (null != compile) { ? ? ? ? ? ? ? ?classBytes.putAll(compile); ? ? ? ? ? } ? ? ? } catch (Exception e) { ? ? ? ? ? ?e.printStackTrace(); ? ? ? } ? } ? ? ?/** ? ? * 編譯 Java 代碼 ? ? */ ? ?private static Map<String, byte[]> compile(String className, String javaCode) { ? ? ? ?JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); ? ? ? ?StandardJavaFileManager stdManager = getStandardFileManager(null, null, null); ? ? ? ?try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) { ? ? ? ? ? ?JavaFileObject javaFileObject = manager.makeStringSource(className, javaCode); ? ? ? ? ? ?JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, Collections.singletonList(javaFileObject)); ? ? ? ? ? ?Boolean result = task.call(); ? ? ? ? ? ?if (result != null && result) { ? ? ? ? ? ? ? ?return manager.getClassBytes(); ? ? ? ? ? } ? ? ? } ? ? ? ?return null; ? } ? ? ?@Override ? ?public Class<?> findClass(String name) throws ClassNotFoundException { ? ? ? ?byte[] buf = classBytes.get(name); ? ? ? ?if (buf == null) { ? ? ? ? ? ?return super.findClass(name); ? ? ? } ? ? ? ?return defineClass(name, buf, 0, buf.length); ? } ? ? ?@Override ? ?public void close() { ? ? ? ?classBytes.clear(); ? ? ? ?CLASSLOADER_MAP.clear(); ? } ? ? ?/** ? ? * 自定義 Java 文件管理器 ? ? */ ? ?public static SpringJavaFileManager getStandardFileManager(DiagnosticListener<? super JavaFileObject> var1, Locale var2, Charset var3) { ? ? ? ?Context var4 = new Context(); ? ? ? ?var4.put(Locale.class, var2); ? ? ? ?if (var1 != null) { ? ? ? ? ? ?var4.put(DiagnosticListener.class, var1); ? ? ? } ? ? ? ?PrintWriter var5 = var3 == null ? new PrintWriter(System.err, true) : new PrintWriter(new OutputStreamWriter(System.err, var3), true); ? ? ? ?var4.put(Log.outKey, var5); ? ? ? ?return new SpringJavaFileManager(var4, true, var3); ? } ? ? ?/** ? ? * 獲取實(shí)例 ? ? */ ? ?public static MemoryClassLoader getInstance() { ? ? ? ?return CLASSLOADER_MAP.get(KEY_CLASSLOADER); ? } ? ? ?/** ? ? * 生成新的實(shí)例 ? ? */ ? ?public static MemoryClassLoader genInstance() { ? ? ? ?MemoryClassLoader classLoader = new MemoryClassLoader(); ? ? ? ?CLASSLOADER_MAP.put(KEY_CLASSLOADER, new MemoryClassLoader()); ? ? ? ?return classLoader; ? } ? ? ?public static String getPath() { ? ? ? ?ApplicationHome home = new ApplicationHome(MemoryJavaFileManager.class); ? ? ? ?String path = home.getSource().getPath(); ? ? ? ?return path; ? } ? ? ?public static boolean isJar() { ? ? ? ?return getPath().endsWith(".jar"); ? } ? }
class MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> { ? ? ?// compiled classes in bytes: ? ?final Map<String, byte[]> classBytes = new HashMap<>(); ? ? ?final Map<String, List<JavaFileObject>> classObjectPackageMap = new HashMap<>(); ? ? ?private JavacFileManager javaFileManager; ? ? ?/** ? ? * key 包名 value javaobj 主要給 jdk 編譯 class 的時(shí)候找依賴 class 用 ? ? */ ? ?public final static Map<String, List<JavaFileObject>> CLASS_OBJECT_PACKAGE_MAP = new HashMap<>(); ? ? ?private static final Object lock = new Object(); ? ? ?private boolean isInit = false; ? ? ?public void init() { ? ? ? ?try { ? ? ? ? ? ?String jarBaseFile = MemoryClassLoader.getPath(); ? ? ? ? ? ?JarFile jarFile = new JarFile(new File(jarBaseFile)); ? ? ? ? ? ?List<JarEntry> entries = jarFile.stream().filter(jarEntry -> jarEntry.getName().endsWith(".jar")).collect(Collectors.toList()); ? ? ? ? ? ?JarFile libTempJarFile; ? ? ? ? ? ?List<JavaFileObject> onePackageJavaFiles; ? ? ? ? ? ?String packageName; ? ? ? ? ? ?for (JarEntry entry : entries) { ? ? ? ? ? ? ? ?libTempJarFile = jarFile.getNestedJarFile(jarFile.getEntry(entry.getName())); ? ? ? ? ? ? ? ?if (libTempJarFile.getName().contains("tools.jar")) { ? ? ? ? ? ? ? ? ? ?continue; ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ?Enumeration<JarEntry> tempEntriesEnum = libTempJarFile.entries(); ? ? ? ? ? ? ? ?while (tempEntriesEnum.hasMoreElements()) { ? ? ? ? ? ? ? ? ? ?JarEntry jarEntry = tempEntriesEnum.nextElement(); ? ? ? ? ? ? ? ? ? ?String classPath = jarEntry.getName().replace("/", "."); ? ? ? ? ? ? ? ? ? ?if (!classPath.endsWith(".class") || jarEntry.getName().lastIndexOf("/") == -1) { ? ? ? ? ? ? ? ? ? ? ? ?continue; ? ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? ? ?packageName = classPath.substring(0, jarEntry.getName().lastIndexOf("/")); ? ? ? ? ? ? ? ? ? ? ? ?onePackageJavaFiles = CLASS_OBJECT_PACKAGE_MAP.containsKey(packageName) ? CLASS_OBJECT_PACKAGE_MAP.get(packageName) : new ArrayList<>(); ? ? ? ? ? ? ? ? ? ? ? ?onePackageJavaFiles.add(new MemorySpringBootInfoJavaClassObject(jarEntry.getName().replace("/", ".").replace(".class", ""), ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?new URL(libTempJarFile.getUrl(), jarEntry.getName()), javaFileManager)); ? ? ? ? ? ? ? ? ? ? ? ?CLASS_OBJECT_PACKAGE_MAP.put(packageName, onePackageJavaFiles); ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? } ? ? ? ? ? } ? ? ? } catch (Exception e) { ? ? ? ? ? ?e.printStackTrace(); ? ? ? } ? ? ? ?isInit = true; ? ? } ? ? ?MemoryJavaFileManager(JavaFileManager fileManager) { ? ? ? ?super(fileManager); ? ? ? ?this.javaFileManager = (JavacFileManager) fileManager; ? } ? ? ?public Map<String, byte[]> getClassBytes() { ? ? ? ?return new HashMap<>(this.classBytes); ? } ? ? ?@Override ? ?public void flush() { ? } ? ? ?@Override ? ?public void close() { ? ? ? ?classBytes.clear(); ? ? ? ?classObjectPackageMap.clear(); ? ? ? ?CLASS_OBJECT_PACKAGE_MAP.clear(); ? } ? ? ? ?public List<JavaFileObject> getLibJarsOptions(String packgeName) { ? ? ? ?synchronized (lock) { ? ? ? ? ? ?if (!isInit) { ? ? ? ? ? ? ? ?init(); ? ? ? ? ? } ? ? ? } ? ? ? ?return CLASS_OBJECT_PACKAGE_MAP.get(packgeName); ? } ? ? ?@Override ? ?public Iterable<JavaFileObject> list(Location location,String packageName, Set<JavaFileObject.Kind> kinds, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? boolean recurse) throws IOException { ? ? ? ?if ("CLASS_PATH".equals(location.getName()) && MemoryClassLoader.isJar()) { ? ? ? ? ? ?List<JavaFileObject> result = getLibJarsOptions(packageName); ? ? ? ? ? ?if (result != null) { ? ? ? ? ? ? ? ?return result; ? ? ? ? ? } ? ? ? } ? ? ? ?Iterable<JavaFileObject> it = super.list(location, packageName, kinds, recurse); ? ? ? ?if (kinds.contains(JavaFileObject.Kind.CLASS)) { ? ? ? ? ? ?final List<JavaFileObject> javaFileObjectList = classObjectPackageMap.get(packageName); ? ? ? ? ? ?if (javaFileObjectList != null) { ? ? ? ? ? ? ? ?if (it != null) { ? ? ? ? ? ? ? ? ? ?for (JavaFileObject javaFileObject : it) { ? ? ? ? ? ? ? ? ? ? ? ?javaFileObjectList.add(javaFileObject); ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ?return javaFileObjectList; ? ? ? ? ? } else { ? ? ? ? ? ? ? ?return it; ? ? ? ? ? } ? ? ? } else { ? ? ? ? ? ?return it; ? ? ? } ? } ? ? ?@Override ? ?public String inferBinaryName(Location location, JavaFileObject file) { ? ? ? ?if (file instanceof MemoryInputJavaClassObject) { ? ? ? ? ? ?return ((MemoryInputJavaClassObject) file).inferBinaryName(); ? ? ? } ? ? ? ?return super.inferBinaryName(location, file); ? } ? ? ?@Override ? ?public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FileObject sibling) throws IOException { ? ? ? ?if (kind == JavaFileObject.Kind.CLASS) { ? ? ? ? ? ?return new MemoryOutputJavaClassObject(className); ? ? ? } else { ? ? ? ? ? ?return super.getJavaFileForOutput(location, className, kind, sibling); ? ? ? } ? } ? ? ?JavaFileObject makeStringSource(String className, final String code) { ? ? ? ?String classPath = className.replace('.', '/') + JavaFileObject.Kind.SOURCE.extension; ? ? ? ?return new SimpleJavaFileObject(URI.create("string:///" + classPath), JavaFileObject.Kind.SOURCE) { ? ? ? ? ? ?@Override ? ? ? ? ? ?public CharBuffer getCharContent(boolean ignoreEncodingErrors) { ? ? ? ? ? ? ? ?return CharBuffer.wrap(code); ? ? ? ? ? } ? ? ? }; ? } ? ? ?void makeBinaryClass(String className, final byte[] bs) { ? ? ? ?JavaFileObject javaFileObject = new MemoryInputJavaClassObject(className, bs); ? ? ? ?String packageName = ""; ? ? ? ?int pos = className.lastIndexOf('.'); ? ? ? ?if (pos > 0) { ? ? ? ? ? ?packageName = className.substring(0, pos); ? ? ? } ? ? ? ?List<JavaFileObject> javaFileObjectList = classObjectPackageMap.get(packageName); ? ? ? ?if (javaFileObjectList == null) { ? ? ? ? ? ?javaFileObjectList = new LinkedList<>(); ? ? ? ? ? ?javaFileObjectList.add(javaFileObject); ? ? ? ? ? ? ?classObjectPackageMap.put(packageName, javaFileObjectList); ? ? ? } else { ? ? ? ? ? ?javaFileObjectList.add(javaFileObject); ? ? ? } ? } ? ? ?class MemoryInputJavaClassObject extends SimpleJavaFileObject { ? ? ? ?final String className; ? ? ? ?final byte[] bs; ? ? ? ? ?MemoryInputJavaClassObject(String className, byte[] bs) { ? ? ? ? ? ?super(URI.create("string:///" + className.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS); ? ? ? ? ? ?this.className = className; ? ? ? ? ? ?this.bs = bs; ? ? ? } ? ? ? ? ?@Override ? ? ? ?public InputStream openInputStream() { ? ? ? ? ? ?return new ByteArrayInputStream(bs); ? ? ? } ? ? ? ? ?public String inferBinaryName() { ? ? ? ? ? ?return className; ? ? ? } ? } ? ? ?class MemoryOutputJavaClassObject extends SimpleJavaFileObject { ? ? ? ?final String className; ? ? ? ? ?MemoryOutputJavaClassObject(String className) { ? ? ? ? ? ?super(URI.create("string:///" + className.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS); ? ? ? ? ? ?this.className = className; ? ? ? } ? ? ? ?@Override ? ? ? ?public OutputStream openOutputStream() { ? ? ? ? ? ?return new FilterOutputStream(new ByteArrayOutputStream()) { ? ? ? ? ? ? ? ?@Override ? ? ? ? ? ? ? ?public void close() throws IOException { ? ? ? ? ? ? ? ? ? ?out.close(); ? ? ? ? ? ? ? ? ? ?ByteArrayOutputStream bos = (ByteArrayOutputStream) out; ? ? ? ? ? ? ? ? ? ?byte[] bs = bos.toByteArray(); ? ? ? ? ? ? ? ? ? ?classBytes.put(className, bs); ? ? ? ? ? ? ? ? ? ?makeBinaryClass(className, bs); ? ? ? ? ? ? ? } ? ? ? ? ? }; ? ? ? } ? } } ?
class MemorySpringBootInfoJavaClassObject extends BaseFileObject { ? ?private final String className; ? ?private URL url; ? ? ?MemorySpringBootInfoJavaClassObject(String className, URL url, JavacFileManager javacFileManager) { ? ? ? ?super(javacFileManager); ? ? ? ?this.className = className; ? ? ? ?this.url = url; ? } ? ? ?@Override ? ?public Kind getKind() { ? ? ? ?return Kind.valueOf("CLASS"); ? } ? ? ?@Override ? ?public URI toUri() { ? ? ? ?try { ? ? ? ? ? ?return url.toURI(); ? ? ? } catch (URISyntaxException e) { ? ? ? ? ? ?e.printStackTrace(); ? ? ? } ? ? ? ?return null; ? } ? ? ?@Override ? ?public String getName() { ? ? ? ?return className; ? } ? ? ?@Override ? ?public InputStream openInputStream() { ? ? ? ?try { ? ? ? ? ? ?return url.openStream(); ? ? ? } catch (IOException e) { ? ? ? ? ? ?e.printStackTrace(); ? ? ? } ? ? ? ?return null; ? } ? ? ?@Override ? ?public OutputStream openOutputStream() throws IOException { ? ? ? ?return null; ? } ? ? ?@Override ? ?public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { ? ? ? ?return null; ? } ? ? ?@Override ? ?public Writer openWriter() throws IOException { ? ? ? ?return null; ? } ? ?@Override ? ?public long getLastModified() { ? ? ? ?return 0; ? } ? ? ?@Override ? ?public boolean delete() { ? ? ? ?return false; ? } ? ? ?@Override ? ?public String getShortName() { ? ? ? ?return className.substring(className.lastIndexOf(".")); ? } ? ?@Override ? ?protected String inferBinaryName(Iterable<? extends File> iterable) { ? ? ? ?return className; ? } ? ? ?@Override ? ?public boolean equals(Object o) { ? ? ? ?return false; ? } ? ? ?@Override ? ?public int hashCode() { ? ? ? ?return 0; ? } ? ? ?@Override ? ?public boolean isNameCompatible(String simpleName, Kind kind) { ? ? ? ?return false; ? } } ?
// 自定義 springboot 的類加載器 class SpringJavaFileManager extends JavacFileManager { ? ?public SpringJavaFileManager(Context context, boolean b, Charset charset) { ? ? ? ?super(context, b, charset); ? } ? ? ?@Override ? ?public ClassLoader getClassLoader(Location location) { ? ? ? ?nullCheck(location); ? ? ? ?Iterable var2 = this.getLocation(location); ? ? ? ?if (var2 == null) { ? ? ? ? ? ?return null; ? ? ? } else { ? ? ? ? ? ?ListBuffer var3 = new ListBuffer(); ? ? ? ? ? ?Iterator var4 = var2.iterator(); ? ? ? ? ? ? ?while (var4.hasNext()) { ? ? ? ? ? ? ? ?File var5 = (File) var4.next(); ? ? ? ? ? ? ? ? ?try { ? ? ? ? ? ? ? ? ? ?var3.append(var5.toURI().toURL()); ? ? ? ? ? ? ? } catch (MalformedURLException var7) { ? ? ? ? ? ? ? ? ? ?throw new AssertionError(var7); ? ? ? ? ? ? ? } ? ? ? ? ? } ? ? ? ? ? ?return this.getClassLoader((URL[]) var3.toArray(new URL[var3.size()])); ? ? ? } ? } ? ? ?protected ClassLoader getClassLoader(URL[] var1) { ? ? ? ?ClassLoader var2 = this.getClass().getClassLoader(); ? ? ? ?try { ? ? ? ? ? ?Class loaderClass = Class.forName("org.springframework.boot.loader.LaunchedURLClassLoader"); ? ? ? ? ? ?Class[] var4 = new Class[]{URL[].class, ClassLoader.class}; ? ? ? ? ? ?Constructor var5 = loaderClass.getConstructor(var4); ? ? ? ? ? ?return (ClassLoader) var5.newInstance(var1, var2); ? ? ? } catch (Throwable var6) { ? ? ? } ? ? ? ?return new URLClassLoader(var1, var2); ? } }
總結(jié)
動(dòng)態(tài)編譯可能在日常工作中所使用的場(chǎng)景不多,但在特定的場(chǎng)景下能夠很好的解決我們所遇到的問題,本篇文章可以給大家提供一些視野,當(dāng)你遇到類似場(chǎng)景時(shí)或許動(dòng)態(tài)編譯能夠很好的解決它!
最后希望大家都能在自己平凡的工作里從編程中收獲一些快樂~
到此這篇關(guān)于Java 動(dòng)態(tài)編譯在項(xiàng)目中的實(shí)踐分享的文章就介紹到這了,更多相關(guān)Java 動(dòng)態(tài)編譯內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot中Elasticsearch的連接配置原理與使用詳解
Elasticsearch是一種開源的分布式搜索和數(shù)據(jù)分析引擎,它可用于全文搜索、結(jié)構(gòu)化搜索、分析等應(yīng)用場(chǎng)景,本文主要介紹了SpringBoot中Elasticsearch的連接配置原理與使用詳解,感興趣的可以了解一下2023-09-09剖析Spring WebFlux反應(yīng)式編程設(shè)計(jì)及工作原理
這篇文章主要為大家介紹了Spring WebFlux反應(yīng)式編程模型工作原理的剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-02-02SpringBoot自定義starter啟動(dòng)器的實(shí)現(xiàn)思路
這篇文章主要介紹了SpringBoot如何自定義starter啟動(dòng)器,通過starter的自定義過程,能夠加深大家對(duì)SpringBoot自動(dòng)配置原理的理解,需要的朋友可以參考下2022-10-10SpringMVC實(shí)現(xiàn)注解式權(quán)限驗(yàn)證的實(shí)例
本篇文章主要介紹了SpringMVC實(shí)現(xiàn)注解式權(quán)限驗(yàn)證的實(shí)例,可以使用Spring MVC中的action攔截器來實(shí)現(xiàn),具有一定的參考價(jià)值,有興趣的可以了解下。2017-02-02