您好,登錄后才能下訂單哦!
Java腳本化API為誰準(zhǔn)備?
腳本語言的一些有用的特性是:
Java 腳本 API 是一種獨立于框架的腳本語言,使用來自于Java代碼的腳本引擎 。通過java腳本API,可以使用Java語言編寫定制/可擴展的應(yīng)用程序并將自定義腳本語言選擇留給最終用戶 。Java 應(yīng)用程序開發(fā)者不需要在開發(fā)過程中選擇擴展語言。如果你使用JSR-223 API來編寫應(yīng)用,那么你的用戶可以使用任何JSR-223兼容的腳本語言。
腳本包
Java 腳本功能是在 javax.script 包中。這是一個比較小的,簡單的API。腳本的出發(fā)點是 ScriptEngineManager 類。一個 ScriptEngineManager 對象可以通過jar文件的服務(wù)發(fā)現(xiàn)機制發(fā)現(xiàn)腳本引擎。它也可以實例化腳本引擎來解釋使用特定的腳本語言編寫的腳本。使用腳本編程接口的最簡單的方法如下:
1.創(chuàng)建一個 ScriptEngineManager 對象
2.從 ScriptEngineManager 獲取 ScriptEngine 對象
3.使用 ScriptEngine的eval方法執(zhí)行腳本
現(xiàn)在,是時候看一些樣本代碼了。了解一些JavaScript有助于閱讀這些例子,但不是強制的。
實例
“Hello,World”
從ScriptEngineManager實例中,我們通過 getEngineByName 方法得到一個JavaScript引擎實例。通過腳本引擎的eval方法來執(zhí)行給定的JavaScript代碼。為簡便起見,本例以及隨后的例子中,我們不對異常進行處理。javax.script API有檢查和運行時異常,你必須妥善處理異常。
import javax.script.*; public class EvalScript { public static void main(String[] args) throws Exception { // create a script engine manager ScriptEngineManager factory = new ScriptEngineManager(); // create a JavaScript engine ScriptEngine engine = factory.getEngineByName("JavaScript"); // evaluate JavaScript code from String engine.eval("print('Hello, World')"); } }
執(zhí)行一個腳本文件
在這個例子中,我們調(diào)用eval方法來接收java.io.Reader作為輸入源。讀入的腳本被執(zhí)行。這種方式能夠成文件執(zhí)行腳本,用相關(guān)的輸入流對象讀取URL和資源。
import javax.script.*; public class EvalFile { public static void main(String[] args) throws Exception { // create a script engine manager ScriptEngineManager factory = new ScriptEngineManager(); // create JavaScript engine ScriptEngine engine = factory.getEngineByName("JavaScript"); // evaluate JavaScript code from given file - specified by first argument engine.eval(new java.io.FileReader(args[0])); } }
假設(shè)我們有一個叫”test.js”的文件,里面的內(nèi)容如下:
println("This is hello from test.js");
我們可以使用下面的方式來運行剛剛的腳本
java EvalFile test.js
腳本變量
當(dāng)你的java應(yīng)用程序嵌入腳本引擎和腳本,你可能希望將您的應(yīng)用程序?qū)ο鬄槿肿兞勘┞队谀_本中。這個例子演示了如何將您的應(yīng)用程序?qū)ο笞鳛槿肿兞勘┞队谀_本中。我們在應(yīng)用程序中創(chuàng)建一個 java.io.File對象作為全局變量,名稱是file。該腳本可以訪問變量,例如,它可以調(diào)用它的公共方法。注意訪問java對象、領(lǐng)域和方法的語法依賴于腳本語言。JavaScript支持最“自然”的類似java的語法。
public class ScriptVars { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); File f = new File("test.txt"); // expose File object as variable to script engine.put("file", f); // evaluate a script string. The script accesses "file" // variable and calls method on it engine.eval("print(file.getAbsolutePath())"); } }
調(diào)用腳本函數(shù)和方法
有些時候,你可能需要多次調(diào)用一個特定腳本函數(shù),例如你的應(yīng)用程序菜單功能可能由腳本來實現(xiàn)。在菜單中的操作事件處理程序中,可能需要調(diào)用一個特定的腳本函數(shù)。下面的示例演示在Java代碼調(diào)用一個特定的腳本。
import javax.script.*; public class InvokeScriptFunction { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); // JavaScript code in a String String script = "function hello(name) { print('Hello, ' + name); }"; // evaluate script engine.eval(script); // javax.script.Invocable is an optional interface. // Check whether your script engine implements or not! // Note that the JavaScript engine implements Invocable interface. Invocable inv = (Invocable) engine; // invoke the global function named "hello" inv.invokeFunction("hello", "Scripting!!" ); } }
如果你的腳本語言是基于對象(如JavaScript)或面向?qū)ο蟮模憧梢栽谀_本對象上調(diào)用腳本方法。
import javax.script.*; public class InvokeScriptMethod { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); // JavaScript code in a String. This code defines a script object 'obj' // with one method called 'hello'. String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }"; // evaluate script engine.eval(script); // javax.script.Invocable is an optional interface. // Check whether your script engine implements or not! // Note that the JavaScript engine implements Invocable interface. Invocable inv = (Invocable) engine; // get script object on which we want to call the method Object obj = engine.get("obj"); // invoke the method named "hello" on the script object "obj" inv.invokeMethod(obj, "hello", "Script Method !!" ); } }
通過腳本實現(xiàn)Java接口
有些時候通過腳本函數(shù)或者方法可以很方便的實現(xiàn)java接口,而不是在Java中調(diào)用。同時,通過接口我們可以避免在很多地方使用javax.script API接口。我們可以得到一個接口實現(xiàn)者對象并將其傳遞給不同的Java api。下面的例子演示了通過腳本實現(xiàn) java.lang.Runnable接口。
import javax.script.*; public class RunnableImpl { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); // JavaScript code in a String String script = "function run() { println('run called'); }"; // evaluate script engine.eval(script); Invocable inv = (Invocable) engine; // get Runnable interface object from engine. This interface methods // are implemented by script functions with the matching name. Runnable r = inv.getInterface(Runnable.class); // start a new thread that runs the script implemented // runnable interface Thread th = new Thread(r); th.start(); } }
如果你的腳本語言是基于對象或者面向?qū)ο蟮?,可以通過腳本對象的腳本方法來實現(xiàn)Java接口。這避免了不得不調(diào)用腳本全局函數(shù)的接口方法。腳本對象可以存儲接口實現(xiàn)狀態(tài)。
import javax.script.*; public class RunnableImplObject { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); // JavaScript code in a String String script = "var obj = new Object(); obj.run = function() { println('run method called'); }"; // evaluate script engine.eval(script); // get script object on which we want to implement the interface with Object obj = engine.get("obj"); Invocable inv = (Invocable) engine; // get Runnable interface object from engine. This interface methods // are implemented by script methods of object 'obj' Runnable r = inv.getInterface(obj, Runnable.class); // start a new thread that runs the script implemented // runnable interface Thread th = new Thread(r); th.start(); } }
腳本的多作用域
在 script variables 例子中,我們看到怎樣將應(yīng)用對象暴露為腳本的全局變量。它有可能暴露為多個全局的作用域 。 單作用域是javax.script.Bindings的實例中. 這個借口派生至java.util.Map<String, Object>。 scope 鍵值對的集合,其中鍵為非空、非空字符串。 多scopes 是 javax.script.ScriptContext 接口支持的。支持一個或多個腳本上下文與相關(guān)的域綁定。默認(rèn)情況下, 每一個腳本引擎都有一個默認(rèn)的腳本上下文。 默認(rèn)的腳本上下文有至少一個域叫 ”ENGINE_SCOPE”。不同域的腳本上下文支持可以通過 getscopes 方法獲取。
import javax.script.*; public class MultiScopes { public static void main(String[] args) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("JavaScript"); engine.put("x", "hello"); // print global variable "x" engine.eval("println(x);"); // the above line prints "hello" // Now, pass a different script context ScriptContext newContext = new SimpleScriptContext(); Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE); // add new variable "x" to the new engineScope engineScope.put("x", "world"); // execute the same script - but this time pass a different script context engine.eval("println(x);", newContext); // the above line prints "world" } }
JavaScript 腳本引擎
Sun的JDK 6中包含了一個基于 Mozilla Rhino JavaScript 腳本引擎。 這個引擎是基于版本為1.6R2的Mozilla Rhino 。多數(shù) Rhino 實現(xiàn)都被包含在內(nèi)。少部分組件由于大小和安全原因被排除了:
1.JavaScript轉(zhuǎn)字節(jié)碼編譯 (也稱 ”優(yōu)化器”).。此功能依賴一個類生成庫。 去掉本功能意味著:JavaScript是解釋執(zhí)行,且不影響腳本執(zhí)行,因為優(yōu)化器是透明的。
2.Rhino的JavaAdapter 也被去掉了。 JavaAdapter是一個JavaScript可擴展Java類和JavaScript可實現(xiàn)Java接口功能。此功能也是需要類生成庫的。我們把Rhino的JavaAdapter替換為Sun實現(xiàn)的JavaAdapter。在Sun的實現(xiàn)中,僅僅實現(xiàn)了JavaScript對象可實現(xiàn)Java單接口功能。例如,下面的代碼會正確執(zhí)行。
var v = new java.lang.Runnable() { run: function() { print('hello'); } } v.run();
在大多數(shù)情況下,JavaAdapter是采用匿名類語法來實現(xiàn)單接口。 使用JavaAdapter來擴展Java類或?qū)崿F(xiàn)多接口并不常見。
3.E4X (ECMAScript for XML – ECMA Standard 357) 被去掉了. 使用XML JavaScript代碼會產(chǎn)生一個語法錯誤. 請注意,E4X支持ECMAScript標(biāo)準(zhǔn)是可選的-省略E4X的實現(xiàn)是被支持也是兼容 ECMAScript 。
4.Rhino的命令行工具 (Rhino shell, debugger 等) 沒有被包含在內(nèi)。但你可以用使用 jrunscript來代替。
JavaScript與Java的通信
在大多數(shù)情況下,訪問Java類、對象和方法很簡單。從JavaScript中訪問屬性和方法與同Java中一樣。這里,我們突出JavaScript Java訪問的重要方面.。更多的細(xì)節(jié)請閱讀http://www.mozilla.org/rhino/scriptjava.html。下面是一些JavaScript訪問Java的代碼片段。本節(jié)需要一些JavaScript知識。如果你打算使用JSR-223中非JavaScript腳本語言,那么本節(jié)可以跳過。
引入Java 包, 類
內(nèi)置的函數(shù)importPackage 和importClass 可以用于引入Java 包和類。
// Import Java packages and classes // like import package.*; in Java importPackage(java.awt); // like import java.awt.Frame in Java importClass(java.awt.Frame); // Create Java Objects by "new ClassName" var frame = new java.awt.Frame("hello"); // Call Java public methods from script frame.setVisible(true); // Access "JavaBean" properties like "fields" print(frame.title);
全局變量Packages也可以用于訪問Java包。
例如: Packages.java.util.Vector, Packages.javax.swing.JFrame. 請注意: ”java” 是 “Packages.java”的快捷引用。還有一些等價的快捷引用前綴 : javax, org, edu, com, net, 所以幾乎所有的 JDK 平臺下的類都可以不使用”Packages” 前綴而訪問到。
請注意,java.lang不是默認(rèn)引入的 (與Java不同),因為會與 JavaScript's 內(nèi)置的 Object, Boolean, Math 等沖突。importPackage 和importClass 函數(shù)”污染” 了JavaScript中的全局變量。為了避免這種情況,你可以使用JavaImporter。
// create JavaImporter with specific packages and classes to import var SwingGui = new JavaImporter(javax.swing, javax.swing.event, javax.swing.border, java.awt.event); with (SwingGui) { // within this 'with' statement, we can access Swing and AWT // classes by unqualified (simple) names. var mybutton = new JButton("test"); var myframe = new JFrame("test"); }
C創(chuàng)建和使用Java的數(shù)組
在JavaScript中,創(chuàng)建一個對象時與Java中一樣,而創(chuàng)建Java數(shù)組時需要顯式的使用Java反射。但一旦創(chuàng)建好后,訪問其中的元素或獲取大小就和Java中一樣。 另外,也可以使用腳本數(shù)組用在Java方法中期望的Java數(shù)組(因為可以自動轉(zhuǎn)換)。所以在大多數(shù)情況下我們不需要顯式地創(chuàng)建Java數(shù)組。
// create Java String array of 5 elements var a = java.lang.reflect.Array.newInstance(java.lang.String, 5); // Accessing elements and length access is by usual Java syntax a[0] = "scripting is great!"; print(a.length);
實現(xiàn)Java 接口
在JavaScript中,可以使用Java匿名類語法形式實現(xiàn)Java中接口:
var r = new java.lang.Runnable() { run: function() { print("running...\n"); } }; // "r" can be passed to Java methods that expect java.lang.Runnable var th = new java.lang.Thread(r); th.start();
當(dāng)接口中只有一個需要實現(xiàn)的方法時,你可以自己傳入腳本的函數(shù)(因為可以自動轉(zhuǎn)換)。
function func() { print("I am func!"); } // pass script function for java.lang.Runnable argument var th = new java.lang.Thread(func); th.start();
重載
Java方法是使用參數(shù)類型重載的。在Java中,重載發(fā)生在編譯階段 (執(zhí)行 javac)。當(dāng)腳本中調(diào)用Java方法時,腳本的翻譯器或編譯器需要選擇適當(dāng)?shù)姆椒?。對于JavaScript引擎,您不需要做任何特別的——正確的Java方法重載變體是根據(jù)參數(shù)類型選擇的。 但有時,您可能希望(或有)顯式地選擇一個特定的過載變體。
var out = java.lang.System.out; // select a particular println function out["println(java.lang.Object)"]("hello");
自定義腳本引擎
我們不會覆蓋的JSR-223兼容腳本引擎實現(xiàn)細(xì)節(jié). 至少, 您需要實現(xiàn)javax.script.ScriptEngine 和javax.script.ScriptEngineFactory 接口。
抽象類javax.script.AbstractScriptEngine 提供了一些ScriptEngine 接口中定義的方法。
在開始實現(xiàn) JSR-223 引擎之前,您可能需要下載 http://scripting.dev.java.net 工程。這個工程維護了一些流行的開源腳本語言的 JSR-223 實現(xiàn)。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。