Java動(dòng)態(tài)編譯執(zhí)行代碼示例
在某些情況下,我們需要?jiǎng)討B(tài)生成java代碼,通過動(dòng)態(tài)編譯,然后執(zhí)行代碼。JAVAAPI提供了相應(yīng)的工具(JavaCompiler)來實(shí)現(xiàn)動(dòng)態(tài)編譯。下面我們通過一個(gè)簡單的例子介紹,如何通過JavaCompiler實(shí)現(xiàn)java代碼動(dòng)態(tài)編譯。
一、獲取JavaCompiler
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
獲取JDK提供的java編譯器,如果沒有提供編譯器,則返回null;
二、編譯
//獲取java文件管理類
StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
//獲取java文件對(duì)象迭代器
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();
當(dāng)我們要編譯的源代碼中,引用了其他代碼,我們需要將引用代碼路徑設(shè)置到-classpath中,否則會(huì)編譯失敗。
三、執(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)建類實(shí)例
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;
}
}
五、測(cè)試
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);
//準(zhǔn)備測(cè)試數(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í)行測(cè)試方法
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);
}
測(cè)試結(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動(dòng)態(tài)編譯執(zhí)行代碼示例的全部內(nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:
java編程進(jìn)行動(dòng)態(tài)編譯加載代碼分享
Java動(dòng)態(tài)規(guī)劃之編輯距離問題示例代碼
Java中的引用和動(dòng)態(tài)代理的實(shí)現(xiàn)詳解
如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
相關(guān)文章
Java VisualVM監(jiān)控遠(yuǎn)程JVM(詳解)
下面小編就為大家?guī)硪黄狫ava VisualVM監(jiān)控遠(yuǎn)程JVM(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10
mybatis-plus 自定義 Service Vo接口實(shí)現(xiàn)數(shù)據(jù)庫實(shí)體與 vo
這篇文章主要介紹了mybatis-plus 自定義 Service Vo接口實(shí)現(xiàn)數(shù)據(jù)庫實(shí)體與 vo 對(duì)象轉(zhuǎn)換返回功能,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-08-08
詳解JAVA中ListIterator和Iterator的辨析
這篇文章主要為大家詳細(xì)介紹了JAVAListIterator和Iterator的辨析,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-02-02
MyBatis的CRUD中的不同參數(shù)綁定查詢實(shí)現(xiàn)
本文主要介紹了MyBatis的CRUD中的不同參數(shù)綁定查詢實(shí)現(xiàn),主要包括單個(gè)參數(shù)傳遞綁定,序號(hào)參數(shù)傳遞綁定,注解參數(shù)傳遞綁定,pojo(對(duì)象)參數(shù)傳遞綁定,map參數(shù)傳遞綁定這幾種類型,具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12
SpringBoot?使用定時(shí)任務(wù)(SpringTask)的詳細(xì)步驟
Cron?表達(dá)式非常靈活,可以滿足各種定時(shí)任務(wù)的需求,但需要注意的是,Cron?表達(dá)式只能表示固定的時(shí)間點(diǎn),無法處理復(fù)雜的時(shí)間邏輯,本文給大家介紹SpringBoot?使用定時(shí)任務(wù)(SpringTask)的詳細(xì)步驟,感興趣的朋友一起看看吧2024-02-02
使用SpringBoot-JPA進(jìn)行自定義保存及批量保存功能
這篇文章主要介紹了使用SpringBoot-JPA進(jìn)行自定義的保存及批量保存功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-06-06
Java多線程(單例模式,堵塞隊(duì)列,定時(shí)器)詳解
這篇文章主要介紹了java多線程的(單例模式,堵塞隊(duì)列,定時(shí)器),具有一定參考價(jià)值,加深多線程編程的理解還是很有幫助的,需要的朋友可以參考下2021-08-08
Java 語言守護(hù)線程 Daemon Thread使用示例詳解
這篇文章主要為大家介紹了Java 語言守護(hù)線程 Daemon Thread使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10

