Rhino
腳本語言有良好的快速開發,高效率的執行,解釋而非編譯執行等優點,并且具有與其他語言編寫的組件之間強大的通信功能。JavaScript 一直是腳本語言中的領頭羊,它是一門具有非常豐富特性的語言。除了瀏覽器之外,JavaScript 也可以應用在其他場合,比如服務器端程序中。Rhino 是使用 Java 語言實現的 JavaScript 引擎。
JavaScript 與瀏覽器完美配合,使得 JavaScript 成為世界上最流行的語言之一。隨著 Web 應用的發展,AJAX 功能實現越來越豐富,JavaScript 也越來越受到人們的關注。新一代瀏覽器正在不斷崛起,HTML5 逐漸成形和發展壯大,JavaScript 也將發揮越來越重要的作用和價值。目前眾多的瀏覽器如 IE8、FireFox4.0 等做出的調整重點基本是針對于 JavaScript 引擎的改進和完善,JavaScript 的受歡迎程度可見一斑。
以簡單的方式快速完成某些復雜的事情通常是創造腳本語言的重要原則,使用腳本語言通常比 C、C++、Java 之類的語言要簡單容易,這也使得腳本語言具有相對于其他程序語言的特性:良好的快速開發,高效率的執行,解釋而非編譯執行,和其它語言編寫的程序組件之間通信功能很強大。
JavaScript 一直是腳本語言的領頭羊,是一門具有非常豐富特性的語言,使用靈活方便,尤其是內置的輕量級數據類型 JSON 使得 JavaScript 更加強大。使得 JavaScript 除了可以在瀏覽器中運行,同樣可以作為應用程序的一部分使用在其他領域。在應用程序中使用 JavaScript 腳本可以為用戶提供自定義公式、自定義單據轉換規則、自定義工作流等功能,同時具有以下優勢:
- 使用靈活方便,有利于快速開發
- 不需要編譯,更新后馬上可以看到運行效果
- 代碼輕量,同樣的程序只需要五分之一至十分之一的代碼量
Rhino 是開源的 JavaScript 引擎,是完全基于 Java 實現,幾乎可以使用 JavaScript 完成 Java 所有的工作。它可以提供強大的計算能力,沒有 I/O 的限制,可以將 JavaScript 編譯成 Java 字節碼,具有良好的速度和性能。在 Rhino 環境中既可以使用 JavaScript 腳本語言,同時也可以非常簡單的使用 Java 語言的某些工具。Rhino 為我們提供了如下功能:
- 對 JavaScript 1.5 的完全支持
- 直接在 Java 中使用 JavaScript 的功能
- 一個 JavaScript shell 用于運行 JavaScript 腳本
- 一個 JavaScript 的編譯器,用于將 JavaScript 編譯成 Java 二進制文件
Rhino 使用
Rhino 環境準備
從 Mazilla 網站上下載 Rhino 引擎(本文撰寫基于最新的版本 Rhino-1.7R3),下載地址為 http://www.mozilla.org/rhino/。將軟件包解壓,可以得到 Rhino 源代碼、文檔、測試代碼、樣例以及一些小工具,利用這些我們便可以通過多種方式執行 JavaScript 腳本。
使用交互模式調用 JS 解釋器
進入交互模式有兩種方式:使用 js.jar 文件實現和使用 org.mozilla.javascript.tools.shell 實現。
打開控制臺,并切換 ja.jar 文件所在的目錄,輸入 java -jar js.jar命令,便會出現解釋器的版本信息,并進入帶提示符 js> 的命令模式。
或切換到 tools 編譯后目錄,輸入 java org.mozilla.javascript.tools.shell.Main,同樣可以進入帶提示符 js> 的命令模式。
創建簡單的 JavaScript 文件 tools.js,其代碼如下:
var tools = {}; tools.testPlus = function(num1 , num2){ return num1 + num2; }在命令行中輸入 load("C:/tools.js"),完成 tools.js 文件的加載。注意在此處"/"和"\"是有區別的,不能換用。
在命令行中輸入 tools.testPlus(1,2),顯示執行結果為 3,證明 JavaScript 代碼運行成功。
退出交互模式可以按 Ctrl+Z(Windows 系統)或 Ctrl+D(Linux 或 Unix 系統)的方式退出,也可以調用 quit()方法退出。
Java 嵌入開發
本部分將向您介紹如何將 Rhino JavaScript 引擎嵌入到您的項目中,從而使您的應用程序增加腳本的支持,提高靈活度。簡單而言,Rhino 的作用在于構造一個 JavaScript 運行所需要的運行環境,亦即下面所用的關鍵詞上下文 Context,下面一步步向您介紹具體使用方式。
在您的 Java 項目中使用 Rhino JavaScript 引擎,首先要做的工作是要將其引入到您的項目中,所需要類都在 org.mozilla.javascript命名空間下,示例如下:
import org.mozilla.javascript.Context; import org.mozilla.javascript.Scriptable;在導入 Rhino JavaScript 的 Java 包之后,需要創建并進入 Context。本步驟的作用在于構造 JavaScript 的運行環境,Context 中儲存了腳本執行的全局環境信息,示例代碼如下:
Context cx = Context.enter();構造 JavaScript 的運行環境非常的簡單,只需要調用 Java 類 Context 的靜態方法 enter 即可,而無需對 Context 類進行實例化,該方法將會返回 Context 的一個實例。
在使用 Rhino 執行腳本之前,必須初始化標準對象(Object,Function 等),示例代碼如下:
Scriptable scope = cx.initStandardObjects();作用域是 JavaScript 中一個相當重要的概念,在本步驟初始化的 scope 變量類似于構造了一個全局對象,而在整個運行過程中 JavaScript 的變量都會作為該對象的一部分,在下文中介紹的在 Java 中調用 JavaScript 變量就是通過該對象實現。初始化標準化對象,需要調用上下文實例的 initStandardObjects 方法,執行結果將會返回一個 Scriptable 實例化對象。
當以上準備工作結束后,便可以正常的執行 JavaScript 腳本,示例代碼如下:
Object result = cx.evaluateString(scope, string, error, num, null);JavaScript 腳本的執行是使用上下文示例中的 evaluateString 方法,執行腳本字符串 string,當腳本中需要使用其它變量時,會在作用域 scope 中尋找所需要的變量,如果發生異常的話則會報告 error 錯誤信息和所在的行號 num,正確執行結束后會返回一個 Object 對象的運行結果。
JavaScript 沒有獨立的輸入輸出方法,必須借助于宿主環境的輸入輸出方法,這里使用 Java 的輸出機制 System.out.println 方法,示例代碼如下:
System.out.println(cx.toString(result));結束上下文是每次使用 Rhino 結束后必須要做的工作,它將移除上下文和當前的線程并做垃圾回收。示例代碼如下:
Context.exit();在每次進入上下文后您都應該調用它退出方法,因為在使用過程中可能會產生異常,所以通常在調用 Context.enter() 進入上下文之后,將退出操作放入對應的 finally 塊中。
在系統開發過程中,我們經常會使用一些 JavaScript 工具包,如加密工具包等。而使用 Rhino 導入工具包也是非常的簡單方便,只需要將工具包文件中的內容以字符的形式在上下文中運行,以后便可以使用對應的作用域中直接使用。示例代碼如下:
Context ct = Context.enter(); Scriptable scope = ct.initStandardObjects(); String filename=System.getProperty("user.dir")+"/demo/test.js"; try { LineNumberReader reader = new LineNumberReader(new FileReader(filename)); String temp = null; StringBuffer sb = new StringBuffer(); while((temp = reader.readLine()) != null){ sb.append(temp).append("\n"); } ct.evaluateString(scope, sb.toString(), null, 1, null); Object result = ct.evaluateString(scope, "test();", null, 1, null); System.out.println(result.toString()); } catch (Exception e) { e.printStackTrace(); } finally{ ct.exit(); }enter(); Scriptable scope = ct.initStandardObjects(); String filename=System.getProperty("user.dir")+"/demo/test.js"; try { LineNumberReader reader = new LineNumberReader(new FileReader(filename)); String temp = null; StringBuffer sb = new StringBuffer(); while((temp = reader.readLine()) != null){ sb.append(temp).append("\n"); } ct.evaluateString(scope, sb.toString(), null, 1, null); Object result = ct.evaluateString(scope, "test();", null, 1, null); System.out.println(result.toString()); } catch (Exception e) { e.printStackTrace(); } finally{ ct.exit(); }Java 和 JavaScript 對象相互調用
從根本上講在 Java 項目中嵌入 JavaScript 腳本引擎,最重要的一點是實現 Java 和 JavaScript 之間的數據共享,而使用 Rhino JavaScript 引擎我們不需要添加任何的代碼和實現,便可以使用 Java 和 JavaScript 對象之間相互調用,例如在 JavaScript 腳本中可以十分方便的去調用 Java 的工具包,而在 Java 中又可以十分方便的去調用 JavaScript 腳本中的變量,從而實現二者之間的無縫結合,提高項目的靈活度,下面將從這兩個方面去詳細介紹實現方式。
將 Java 部分代碼或者功能實現作為 JavaScript 一部分,以腳本的方式執行,這種方式在極大程度上可以減少用戶為解決個別問題而費盡腦筋。在 JavaScript 中可以直接使用 Java 對象,示例代碼如下:
Context ct = Context.enter(); Scriptable scope = ct.initStandardObjects(); String str = "var test={};"; str += "test.call=function(){return 'Successful!';};"; str += "java.lang.System.out.println(test.call())"; ct.evaluateString(scope, str, null, 1, null);在上述實例代碼中實現了在 JavaScript 代碼中直接調用 Java 的輸出方法,這種方式可能從感覺上不是很舒服,因為需要明確定義 Java 的命名空間等信息。另外,也可以將 Java 對象轉換為 JavaScript 對象,并添加到運行環境中,需要添加額外的代碼去實現,這種方式有點像 Java 工具包的導入,示例代碼如下:
Context ct = Context.enter(); Scriptable scope = ct.initStandardObjects(); Object out = Context.javaToJS(System.out, scope); ScriptableObject.putProperty(scope, "out", out); ct.evaluateString(scope, "out.println('Successful!')", null, 1, null);在 Java 中若要取得 JavaScript 腳本的運行結果非常的簡單,在前面的文字中我們已經探討過,使用運行返回的結果即可。然而在項目開發中我們或許常常會希望獲得一些額外的信息,比如運行過程中的一些臨時信息,無法作為最終結果返回時,本部分將是您特別希望得到的,而本部分的實現十分簡單,簡單的幾行代碼便可以實現。示例代碼如下:
Context ct = Context.enter(); Scriptable scope = ct.initStandardObjects(); ct.evaluateString(scope, "var test = 'Successful';", null, 1, null); Object jsObject = scope.get("test" , scope); if (jsObject == Scriptable.NOT_FOUND) { System.out.println("test is not defined."); } else { System.out.println("test is " + Context.toString(jsObject)); }在上述的示例代碼中,我們同樣用到了 scope 變量,這個是 JavaScript 運行時的全局變量,您可以將它理解成為一個容器,里面包含了 JavaScript 運行過程中的所有信息,所以在您希望取得 JavaScript 過程中的某些信息時,請首先考慮該對象。
在前文中我們已經向您展示了如何將 Java 代碼以 JavaScript 腳本的方式運行,同樣我們也可以將 JavaScript 腳本作為 Java 代碼進行實現,這樣可以使您的項目復用度極大提高,也將會使您在項目開發過程中更加得心應手,示例代碼如下:
Context ct = Context.enter(); Scriptable scope = ct.initStandardObjects(); ct.evaluateString(scope, "function test(name){return 'Successful!' + name;}", null, 1, null);Object functionObject = scope.get("test" , scope); if (!(functionObject instanceof Function)) { System.out.println("test is undefined or not a function."); } else { Object testArgs[] = {"Ceven"}; Function test = (Function)functionObject; Object result = test.call(ct, scope, scope, testArgs); System.out.println(Context.toString(result)); }?
最后歡迎大家訪問我的個人網站:?1024s
總結
- 上一篇: 简述UIView的属性和用法
- 下一篇: Stream操作时Collectors工