在某些情況下,我們需要動態生成java代碼,通過動態編譯,然後執行代碼。 JAVAAPI提供了相應的工具(JavaCompiler)來實現動態編譯。下面我們通過一個簡單的例子介紹,如何通過JavaCompiler實現java代碼動態編譯。
一、獲取JavaCompiler
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
獲取JDK提供的java編譯器,如果沒有提供編譯器,則返回null;
二、編譯
//獲取java文件管理類StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);//獲取java文件對象迭代器Iterable<? extends JavaFileObject> it = manager.getJavaFileObjects(files);//設置編譯參數ArrayList<String> ops = new ArrayList<String>();ops.add("-Xlint:unchecked");//設置classpathops.add("-classpath");ops.add(CLASS_PATH);//獲取編譯任務JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, ops, null, it);//執行編譯任務task.call();當我們要編譯的源代碼中,引用了其他代碼,我們需要將引用代碼路徑設置到-classpath中,否則會編譯失敗。
三、執行
//要加載的類名String className = "xxx.xxx.xxx";//獲取類加載器ClassLoader classLoader = XXX.class.getClassLoader();//加載類Class<?> cls = classLoader.loadClass(className);//調用方法名稱String methodName = "execute";//方法參數類型數組Class<?>[] paramCls = {...};//獲取方法Method method = cls.getDeclaredMethod(methodName , paramCls);//創建類實例Object obj = cls.newInstance();//方法參數Object[] params = {...};//調用方法Object result = method.invoke(obj, params);四、完整代碼
//ClassUtil.javaimport 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 編譯參數* @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 編譯參數* @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;}/** * 調用類方法* @param cls 類* @param methodName 方法名* @param paramsCls 方法參數類型* @param params 方法參數* @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");//設置編譯參數ArrayList<String> ops = new ArrayList<String>();ops.add("-Xlint:unchecked");//編譯代碼,返回classClass<?> cls = ClassUtil.loadClass("/com/even/test/Sum.java",sb.toString(),"com.even.test.Sum",ops);//準備測試數據Map<String,double> data = new HashMap<String,double>();data.put("f1", 10.0);data.put("f2", 20.0);data.put("f3", 30.0);//執行測試方法Object result = ClassUtil.invoke(cls, "calculate", new Class[]{Map.class}, new Object[]{data});//輸出結果logger.debug(data);logger.debug("(30*f1+20*f2+50*f3)/100 = "+result);}測試結果
16:12:02.860 DEBUG com.even.tools.ClassUtil - Write Java Source Code to: .../classes//com/even/test/Sum.java16:12:03.544 DEBUG com.even.tools.ClassUtil - Compile Java File:.../classes//com/even/test/Sum.java16:12:03.545 DEBUG com.even.tools.ClassUtil - Load Class[com.even.test.Sum] by sun.misc.Launcher$AppClassLoader@73d16e9316: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總結
以上就是本文關於Java動態編譯執行代碼示例的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站:
java編程進行動態編譯加載代碼分享
Java動態規劃之編輯距離問題示例代碼
Java中的引用和動態代理的實現詳解
如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!