出現的問題:java
我用spring boot搭建一個web環境,想實現動態加載一個外部的java文件,編譯並運行獲得結果。web
大概代碼以下:spring
/** * * <p>Title: compile</p> * <p>Description: compile </p> * @param javaName javaName the name of your public class,eg: <code>TestClass.java</code> * @param javaSrc source code string * @return return the Map, the KEY means ClassName, the VALUE means bytecode. */ public static Map<String, byte[]> compile(String javaName, String javaSrc) { // 獲取jvm的jre JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager stdManager = compiler.getStandardFileManager(null, null, null); try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) { JavaFileObject javaFileObject = manager.makeStringSource(javaName, javaSrc); // 用來獲取編譯錯誤時的錯誤信息 DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>(); JavaCompiler.CompilationTask task = compiler.getTask(null, manager, collector, null, null, Arrays.asList(javaFileObject)); if (task.call()) { return manager.getClassBytes(); } else { // 當編譯存在錯誤的時候,打印錯誤日誌 collector.getDiagnostics().forEach(item -> log.error(item.toString())); } // 關閉StandardJavaFileManager stdManager.close(); } catch (IOException e) { log.error("出現異常 : " , e); } return null; }
可是,我外部的java文件是含有第三方jar包的(這些jar包,個人spring boot工程所有含有)。tomcat
在eclipse下運行時,一切順利,但當我將spring boot打包成jar包,使用java -jar 的方式運行的時候,這段代碼在編譯java文件時出錯,提示app
error: package org.jsoup does not exist import org.jsoup.Jsoup;
解決方法:eclipse
1. 不能使用jar包部署(樓主找了好久都沒找到jar包這麼解決,因此放棄了,有知道的大佬幫忙補充一下。)jvm
本例子使用war包的方式部署到tomcat上。編輯器
2. 修改以上代碼,編譯時加入編譯屬性:ide
/** * * <p>Title: compile</p> * <p>Description: compile </p> * @param javaName javaName the name of your public class,eg: <code>TestClass.java</code> * @param javaSrc source code string * @return return the Map, the KEY means ClassName, the VALUE means bytecode. */ public static Map<String, byte[]> compile(String javaName, String javaSrc) { // 獲取jvm的jre JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager stdManager = compiler.getStandardFileManager(null, null, null); try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) { JavaFileObject javaFileObject = manager.makeStringSource(javaName, javaSrc); // 用來獲取編譯錯誤時的錯誤信息 DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>(); /** START 如下代碼在打包成web程序時必須開啓,在編輯器裏面時請屏蔽 */ StringBuilder cp = new StringBuilder(); URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader(); for (URL url : urlClassLoader.getURLs()) { cp.append(url.getFile()).append(File.pathSeparator); } List<String> options = new ArrayList<String>(); options.add("-classpath"); options.add(cp.toString()); /** END 以上代碼在打包成web程序時必須開啓,在編輯器裏面時請屏蔽 */ // 此處的options 只有打包成web服務時,才須要,在編輯器中運行時,直接填null便可。 JavaCompiler.CompilationTask task = compiler.getTask(null, manager, collector, options, null, Arrays.asList(javaFileObject)); if (task.call()) { return manager.getClassBytes(); } else { // 當編譯存在錯誤的時候,打印錯誤日誌 collector.getDiagnostics().forEach(item -> log.error(item.toString())); } // 關閉StandardJavaFileManager stdManager.close(); } catch (IOException e) { log.error("出現異常 : " , e); } return null; }
3. 請注意,在編輯器中運行時,加入 options 會致使運行失敗,因此在編輯器中請屏蔽掉,發佈時再打開。ui