Java動態(tài)編譯執(zhí)行代碼示例
在某些情況下,我們需要動態(tài)生成java代碼,通過動態(tài)編譯,然后執(zhí)行代碼。JAVAAPI提供了相應的工具(JavaCompiler)來實現(xiàn)動態(tài)編譯。下面我們通過一個簡單的例子介紹,如何通過JavaCompiler實現(xiàn)java代碼動態(tài)編譯。
一、獲取JavaCompiler
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
獲取JDK提供的java編譯器,如果沒有提供編譯器,則返回null;
二、編譯
//獲取java文件管理類 StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null); //獲取java文件對象迭代器 Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files); //設(shè)置編譯參數(shù) ArrayList<String> ops = new ArrayList<String>(); ops.add("-Xlint:unchecked"); //設(shè)置classpath ops.add("-classpath"); ops.add(CLASS_PATH); //獲取編譯任務(wù) JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it); //執(zhí)行編譯任務(wù) task.call();
當我們要編譯的源代碼中,引用了其他代碼,我們需要將引用代碼路徑設(shè)置到-classpath中,否則會編譯失敗。
三、執(zhí)行
//要加載的類名 String className = "xxx.xxx.xxx"; //獲取類加載器 ClassLoader classLoader = XXX.class.getClassLoader(); //加載類 Class<?> cls = classLoader.loadClass(className); //調(diào)用方法名稱 String methodName = "execute"; //方法參數(shù)類型數(shù)組 Class<?>[] paramCls = {...}; //獲取方法 Method method = cls.getDeclaredMethod(methodName , paramCls); //創(chuàng)建類實例 Object obj = cls.newInstance(); //方法參數(shù) Object[] params = {...}; //調(diào)用方法 Object result = method.invoke(obj, params);
四、完整代碼
//ClassUtil.java import java.io.FileWriter; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.util.ArrayList; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class ClassUtil { private static final Log logger = LogFactory.getLog(ClassUtil.class); private static JavaCompiler compiler; static{ compiler = ToolProvider.getSystemJavaCompiler(); } /** * 獲取java文件路徑 * @param file * @return */ private static String getFilePath(String file){ int last1 = file.lastIndexOf('/'); int last2 = file.lastIndexOf('\\'); return file.substring(0, last1>last2?last1:last2)+File.separatorchar; } /** * 編譯java文件 * @param ops 編譯參數(shù) * @param files 編譯文件 */ private static void javac(List<String> ops,String... files){ StandardJavaFileManager manager = null; try{ manager = compiler.getStandardFileManager(null, null, null); Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files); JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it); task.call(); if(logger.isDebugEnabled()){ for (String file:files) logger.debug("Compile Java File:" + file); } } catch(Exception e){ logger.error(e); } finally{ if(manager!=null){ try { manager.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 生成java文件 * @param file 文件名 * @param source java代碼 * @throws Exception */ private static void writeJavaFile(String file,String source)throws Exception{ if(logger.isDebugEnabled()){ logger.debug("Write Java Source Code to:"+file); } BufferedWriter bw = null; try{ File dir = new File(getFilePath(file)); if(!dir.exists()) dir.mkdirs(); bw = new BufferedWriter(new FileWriter(file)); bw.write(source); bw.flush(); } catch(Exception e){ throw e; } finally{ if(bw!=null){ bw.close(); } } } /** * 加載類 * @param name 類名 * @return */ private static Class<?> load(String name){ Class<?> cls = null; ClassLoader classLoader = null; try{ classLoader = ClassUtil.class.getClassLoader(); cls = classLoader.loadClass(name); if(logger.isDebugEnabled()){ logger.debug("Load Class["+name+"] by "+classLoader); } } catch(Exception e){ logger.error(e); } return cls; } /** * 編譯代碼并加載類 * @param filePath java代碼路徑 * @param source java代碼 * @param clsName 類名 * @param ops 編譯參數(shù) * @return */ public static Class<?> loadClass(String filePath,String source,String clsName,List<String> ops){ try { writeJavaFile(CLASS_PATH+filePath,source); javac(ops,CLASS_PATH+filePath); return load(clsName); } catch (Exception e) { logger.error(e); } return null; } /** * 調(diào)用類方法 * @param cls 類 * @param methodName 方法名 * @param paramsCls 方法參數(shù)類型 * @param params 方法參數(shù) * @return */ public static Object invoke(Class<?> cls,String methodName,Class<?>[] paramsCls,Object[] params){ Object result = null; try { Method method = cls.getDeclaredMethod(methodName, paramsCls); Object obj = cls.newInstance(); result = method.invoke(obj, params); } catch (Exception e) { logger.error(e); } return result; } }
五、測試
public class ClassUtilTest { private static final Log logger = LogFactory.getLog(ClassUtilTest.class); public static void main(String args[]){ StringBuilder sb = new StringBuilder(); sb.append("package com.even.test;"); sb.append("import java.util.Map;\nimport java.text.DecimalFormat;\n"); sb.append("public class Sum{\n"); sb.append("private final DecimalFormat df = new DecimalFormat(\"#.#####\");\n"); sb.append("public Double calculate(Map<String,Double> data){\n"); sb.append("double d = (30*data.get(\"f1\") + 20*data.get(\"f2\") + 50*data.get(\"f3\"))/100;\n"); sb.append("return Double.valueOf(df.format(d));}}\n"); //設(shè)置編譯參數(shù) ArrayList<String> ops = new ArrayList<String>(); ops.add("-Xlint:unchecked"); //編譯代碼,返回class Class<?> cls = ClassUtil.loadClass("/com/even/test/Sum.java",sb.toString(),"com.even.test.Sum",ops); //準備測試數(shù)據(jù) Map<String,double> data = new HashMap<String,double>(); data.put("f1", 10.0); data.put("f2", 20.0); data.put("f3", 30.0); //執(zhí)行測試方法 Object result = ClassUtil.invoke(cls, "calculate", new Class[]{Map.class}, new Object[]{data}); //輸出結(jié)果 logger.debug(data); logger.debug("(30*f1+20*f2+50*f3)/100 = "+result); }
測試結(jié)果
16:12:02.860 DEBUG com.even.tools.ClassUtil - Write Java Source Code to: .../classes//com/even/test/Sum.java 16:12:03.544 DEBUG com.even.tools.ClassUtil - Compile Java File:.../classes//com/even/test/Sum.java 16:12:03.545 DEBUG com.even.tools.ClassUtil - Load Class[com.even.test.Sum] by sun.misc.Launcher$AppClassLoader@73d16e93 16:12:03.547 DEBUG com.even.test.ClassUtilTest - {f1=10.0, f2=20.0, f3=30.0} 16:12:03.547 DEBUG com.even.test.ClassUtilTest - (30*f1+20*f2+50*f3)/100 = 22.0
總結(jié)
以上就是本文關(guān)于Java動態(tài)編譯執(zhí)行代碼示例的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:
如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
相關(guān)文章
Java VisualVM監(jiān)控遠程JVM(詳解)
下面小編就為大家?guī)硪黄狫ava VisualVM監(jiān)控遠程JVM(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10mybatis-plus 自定義 Service Vo接口實現(xiàn)數(shù)據(jù)庫實體與 vo
這篇文章主要介紹了mybatis-plus 自定義 Service Vo接口實現(xiàn)數(shù)據(jù)庫實體與 vo 對象轉(zhuǎn)換返回功能,本文通過實例圖文相結(jié)合給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧2024-08-08詳解JAVA中ListIterator和Iterator的辨析
這篇文章主要為大家詳細介紹了JAVAListIterator和Iterator的辨析,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-02-02MyBatis的CRUD中的不同參數(shù)綁定查詢實現(xiàn)
本文主要介紹了MyBatis的CRUD中的不同參數(shù)綁定查詢實現(xiàn),主要包括單個參數(shù)傳遞綁定,序號參數(shù)傳遞綁定,注解參數(shù)傳遞綁定,pojo(對象)參數(shù)傳遞綁定,map參數(shù)傳遞綁定這幾種類型,具有一定的參考價值,感興趣的可以了解一下2023-12-12SpringBoot?使用定時任務(wù)(SpringTask)的詳細步驟
Cron?表達式非常靈活,可以滿足各種定時任務(wù)的需求,但需要注意的是,Cron?表達式只能表示固定的時間點,無法處理復雜的時間邏輯,本文給大家介紹SpringBoot?使用定時任務(wù)(SpringTask)的詳細步驟,感興趣的朋友一起看看吧2024-02-02使用SpringBoot-JPA進行自定義保存及批量保存功能
這篇文章主要介紹了使用SpringBoot-JPA進行自定義的保存及批量保存功能,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-06-06Java 語言守護線程 Daemon Thread使用示例詳解
這篇文章主要為大家介紹了Java 語言守護線程 Daemon Thread使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10