Java 動態(tài)編譯在項目中的實踐分享
1、什么是動態(tài)編譯
在 Java 中,動態(tài)編譯是指在運行時動態(tài)地編譯 Java 源代碼,生成字節(jié)碼,并加載到 JVM 中執(zhí)行。動態(tài)編譯可以用于實現(xiàn)動態(tài)代碼生成、動態(tài)加載、插件化等功能。
1.1、動態(tài)編譯的相關概念
JavaFileManager 對象:用于管理編譯過程中的文件。
- JavaFileManager 是一個接口,提供了對 Java 文件的管理功能,包括創(chuàng)建、查找、讀寫等操作。JavaFileManager 有多種實現(xiàn)方式,例如 StandardJavaFileManager、ForwardingJavaFileManager 等。
DiagnosticListener 對象:用于收集編譯時的診斷信息。
- DiagnosticListener 是一個接口,用于接收編譯時的診斷信息,例如錯誤、警告等。
JavaFileObject 對象:表示要編譯的 Java 源代碼。
- JavaFileObject 是一個抽象類,用于表示 Java 源代碼或字節(jié)碼。JavaFileObject 有多種實現(xiàn)方式,例如 SimpleJavaFileObject、JavaFileObjectWrapper 等。
1.2、如何簡單的實現(xiàn)動態(tài)編譯
- 創(chuàng)建一個 JavaCompiler 對象,該對象用于編譯 Java 源代碼。
- 創(chuàng)建一個 DiagnosticCollector 對象,該對象用于收集編譯時的診斷信息。
- 創(chuàng)建一個 JavaFileManager 對象,該對象用于管理編譯過程中的文件。
- 創(chuàng)建一個 JavaFileObject 對象,該對象用于表示要編譯的 Java 源代碼。
- 調(diào)用 JavaCompiler 對象的 getTask 方法,傳入 JavaFileManager 對象和 DiagnosticCollector 對象,獲取一個 CompilationTask 對象。
- 調(diào)用 CompilationTask 對象的 call 方法,編譯 Java 源代碼。
- 獲取 DiagnosticCollector 對象的診斷信息,并處理編譯結(jié)果。
下面是一個簡單的示例,演示如何使用動態(tài)編譯:
public class DynamicCompiler {
? ?public static void main(String[] args) throws Exception {
? ? ? ?// 創(chuàng)建 JavaCompiler 對象
? ? ? ?JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
? ? ? ?// 創(chuàng)建 DiagnosticCollector 對象,用于收集編譯時的診斷信息
? ? ? ?DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
? ? ? ?// 創(chuàng)建 JavaFileManager 對象,用于管理編譯過程中的文件
? ? ? ?StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
? ? ? ?// 創(chuàng)建 JavaFileObject 對象,用于表示要編譯的 Java 源代碼
? ? ? ?String code = "public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } }";
? ? ? ?JavaFileObject source = new JavaSourceFromString("HelloWorld", code);
? ? ? ?// 獲取 CompilationTask 對象
? ? ? ?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;
? }
}運行結(jié)果:
Hello World!
Compilation was successful.
2、如何結(jié)合 springboot 項目使用
上面展示了如何簡單使用 Java 的動態(tài)編譯功能,但是在日常項目開發(fā)中,會面對更多的場景。結(jié)合前言中我所遇到的問題,我簡單的給大家介紹下我在項目中是如何使用 Java 的動態(tài)編譯功能來解決我所遇到的問題的。
我當時的想法是這樣的:

這樣,各個業(yè)務方就可以自己管理自己的代碼塊,與外部對接或者修改代碼無需在發(fā)布應用,徹底解放了我,讓我有更多的精力給公司做更重要的事情!
2.1、動態(tài)編譯在項目中遇到的問題
2.1.1、必須重寫類加載器新編譯的代碼才能生效
在 Java 中使用動態(tài)編譯功能時,重寫類加載器是必要的。這是因為動態(tài)編譯生成的類需要加載到 JVM 中執(zhí)行,而默認的類加載器無法加載動態(tài)生成的類。
在 Java 中,類加載器分為三種:啟動類加載器、擴展類加載器和應用程序類加載器。默認情況下,Java 使用應用程序類加載器來加載類。應用程序類加載器只能加載預先編譯好的類,無法加載動態(tài)生成的類。因此,我們需要重寫類加載器,使其能夠加載動態(tài)生成的類。
重寫類加載器有兩種方式:繼承 ClassLoader 類或?qū)崿F(xiàn) ClassLoader 接口。一般情況下,我們建議使用繼承 ClassLoader 類的方式,因為這樣可以更方便地控制類加載的過程。
當我們重寫類加載器時,需要實現(xiàn) findClass 方法。findClass 方法用于查找指定名稱的類。如果類已經(jīng)被加載過,可以直接返回已加載的類;否則,需要使用動態(tài)編譯生成類的字節(jié)碼,并通過 defineClass 方法將其加載到 JVM 中執(zhí)行。
2.1.2、沒有依賴的簡單代碼可以編譯成功,但是一旦有依賴關系,編譯就會失敗
Java 編譯器是通過 JavaFileManager 來加載相關依賴類的,如果不重寫使用的是默認的 JavaFileManager 來獲取 springboot 的 jarFile 來讀取嵌套 jar,自然是獲取不到的,需要我們重寫 JavaFileManager,去獲取編譯代碼所需的依賴,具體寫法詳見 2.2 代碼示例。
2.2、代碼示例
?// 通過調(diào)用這個方法即可實現(xiàn) java 的動態(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";
?
? ?/**
? ? * 注冊 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);
? }
?
? ?/**
? ? * 獲取實例
? ? */
? ?public static MemoryClassLoader getInstance() {
? ? ? ?return CLASSLOADER_MAP.get(KEY_CLASSLOADER);
? }
?
? ?/**
? ? * 生成新的實例
? ? */
? ?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 的時候找依賴 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é)
動態(tài)編譯可能在日常工作中所使用的場景不多,但在特定的場景下能夠很好的解決我們所遇到的問題,本篇文章可以給大家提供一些視野,當你遇到類似場景時或許動態(tài)編譯能夠很好的解決它!
最后希望大家都能在自己平凡的工作里從編程中收獲一些快樂~
到此這篇關于Java 動態(tài)編譯在項目中的實踐分享的文章就介紹到這了,更多相關Java 動態(tài)編譯內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot中Elasticsearch的連接配置原理與使用詳解
Elasticsearch是一種開源的分布式搜索和數(shù)據(jù)分析引擎,它可用于全文搜索、結(jié)構(gòu)化搜索、分析等應用場景,本文主要介紹了SpringBoot中Elasticsearch的連接配置原理與使用詳解,感興趣的可以了解一下2023-09-09
SpringBoot自定義starter啟動器的實現(xiàn)思路
這篇文章主要介紹了SpringBoot如何自定義starter啟動器,通過starter的自定義過程,能夠加深大家對SpringBoot自動配置原理的理解,需要的朋友可以參考下2022-10-10

