這篇文章主要介紹“JDK6動態(tài)編譯的方法是什么”的相關(guān)知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“JDK6動態(tài)編譯的方法是什么”文章能幫助大家解決問題。
西充網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)公司!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)公司等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)公司2013年至今到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)公司。
JDK6開始提供了動態(tài)編譯的API,在許多應(yīng)用場景都可以用得著,如動態(tài)加載(修改)服務(wù)、高性動態(tài)業(yè)務(wù)邏輯實現(xiàn)(用腳本或模板引擎實現(xiàn)效率滿足不了需求)等都非常好用。
API對應(yīng)的接口都在javax.tools包下面,常用編譯方式有基于文本文件、內(nèi)存字符串等,實際上基于URI的字節(jié)流都可以,也就是遠程Java源代碼也可以。對于常用的已有文件形式的動態(tài)編譯網(wǎng)上的實例已經(jīng)非常多,我在這里介紹下動態(tài)編譯內(nèi)存中以字符串的形式。
簡單的代碼流程如下:
Java代碼
//通過系統(tǒng)工具提供者獲得動態(tài)編譯器 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); //獲得一個文件管理器,它的功能主要是提供所有文件操作的規(guī)則, //如源代碼路徑、編譯的classpath,class文件目標目錄等,其相關(guān)屬性都提供默認值 StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); //獲得CompilationTask并調(diào)用 //獲得CompilationTask方法原型: getTask(Writer out, JavaFileManager fileManager, DiagnosticListener super JavaFileObject> diagnosticListener, Iterable options, Iterable classes, Iterable extends JavaFileObject> compilationUnits) //簡單調(diào)用例子 boolean b = jc.getTask(null, fileManager, null, null, null, compilationUnits).call();
我這里介紹的字符串形式的編譯(其它方式也會有相似的具體實現(xiàn)),還需要提供一個FileObject一個實現(xiàn)類,將相應(yīng)的對象封裝作為getTask()的最后一個參數(shù)來構(gòu)建具體的編譯Task.
JavaDoc提供的一個FileObject參考實現(xiàn):
Class JavaSourceFromString
Java代碼
import java.net.URI; import javax.tools.SimpleJavaFileObject; public class JavaSourceFromString extends SimpleJavaFileObject { /** * 源碼 */ final String code; /** * 構(gòu)造方法:從字符串中構(gòu)造一個FileObject * @param name the name of the compilation unit represented by this file object * @param code the source code for the compilation unit represented by this file object */ 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; } }
完整的測試類:
Class TestDyCompile
Java代碼
import java.io.File; import java.io.IOException; import java.util.Arrays; import javax.tools.JavaCompiler; import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import javax.tools.ToolProvider; import dyclass.Test; public class TestDyCompile { /** * * @author ZhangXiang * @param args * 2011-4-7 */ public static void main(String[] args) { StringBuilder classStr = new StringBuilder("package dyclass;public class Foo implements Test{"); classStr.append("public void test(){"); classStr.append("System.out.println(\"Foo2\");}}"); JavaCompiler jc = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = jc.getStandardFileManager(null, null, null); Location location = StandardLocation.CLASS_OUTPUT; File[] outputs = new File[]{new File("bin/")}; try { fileManager.setLocation(location, Arrays.asList(outputs)); } catch (IOException e) { e.printStackTrace(); } JavaFileObject jfo = new JavaSourceFromString("dyclass.Foo", classStr.toString()); JavaFileObject[] jfos = new JavaFileObject[]{jfo}; Iterable extends JavaFileObject> compilationUnits = Arrays.asList(jfos); boolean b = jc.getTask(null, fileManager, null, null, null, compilationUnits).call(); if(b){//如果編譯成功 try { Test t = (Test) Class.forName("dyclass.Foo").newInstance(); t.test(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } }
我在這里的具體業(yè)務(wù)類為dyclass.Foo,也就是我們需要動態(tài)編譯的類,為了方便寫業(yè)務(wù)的調(diào)用代碼,也可以讓我們的業(yè)務(wù)類實現(xiàn)一個接口,然后通過反射獲得具體子類強制轉(zhuǎn)換來調(diào)用。
Test接口:
Java代碼
public interface Test { //業(yè)務(wù)方法簽名 void test(); }
另外,在代碼中還有這么一段:
Java代碼
Location location = StandardLocation.CLASS_OUTPUT; File[] outputs = new File[]{new File("bin/")}; try { fileManager.setLocation(location, Arrays.asList(outputs)); } catch (IOException e) { e.printStackTrace(); }
這段代碼的作用相信大家一看到它就想到它的作用了,前面有說過JavaFileManager 的作用,我在這里設(shè)置了CLASS文件的輸出目錄,意圖很簡單,我的工程是在Eclipse運行的,項目的目標路徑就是項目下的bin目錄,如果不設(shè)置的話,class文件輸出路徑即為默認值,也就是直接在項目根路徑下,后面直接調(diào)用就不能完成了。當然在其它一些應(yīng)用場景中需要設(shè)置為自己需要的目錄。
同樣的方法可以設(shè)置JavaFileManager 其它的我們需要的文件規(guī)則屬性(可以參照枚舉類型StandardLocation),在這里就不一一介紹了。
關(guān)于“JDK6動態(tài)編譯的方法是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,小編每天都會為大家更新不同的知識點。