![]() |
|
Java SE 6 引入了對 Java Specification Request(JSR)223 的支持,JSR 223 旨在定義一個統一的規范,使得 Java 應用程序可以通過一套固定的接口與各種腳本引擎交互,從而達到在 Java 平臺上調用各種腳本語言的目的。javax.script
包定義了這些接口,即 Java 腳本編程 API。Java 腳本 API 的目標與 Apache 項目 Bean Script
Framework(BSF)類似,通過它 Java 應用程序就能通過虛擬機調用各種腳本,同時,腳本語言也能訪問應用程序中的 Java
對象和方法。Java 腳本 API 是連通 Java 平臺和腳本語言的橋梁。首先,通過它為數眾多的現有 Java
庫就能被各種腳本語言所利用,節省了開發成本縮短了開發周期;其次,可以把一些復雜異變的業務邏輯交給腳本語言處理,這又大大提高了開發效率。
在 javax.script
包中定義的實現類并不多,主要是一些接口和對應的抽象類,圖 1 顯示了其中包含的各個接口和類。
圖 1. javax.script 包概況

這 個包的具體實現類少的根本原因是這個包只是定義了一個編程接口的框架規范,至于對如何解析運行具體的腳本語言,還需要由第三方提供實現。雖然這些腳本引擎 的實現各不相同,但是對于 Java 腳本 API 的使用者來說,這些具體的實現被很好的隔離隱藏了。Java 腳本 API 為開發者提供了如下功能:
- 獲取腳本程序輸入,通過腳本引擎運行腳本并返回運行結果,這是最核心的接口。
- 發現腳本引擎,查詢腳本引擎信息。
- 通過腳本引擎的運行上下文在腳本和 Java 平臺間交換數據。
- 通過 Java 應用程序調用腳本函數。
在詳細介紹這四個功能之前,我們先通過一個簡單的例子來展示如何通過 Java 語言來運行腳本程序,這里仍然以經典的“Hello World”開始。
清單 1. Hello World
public class HelloWorld {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
engine.eval("print ('Hello World')");
}
}
這個例子非常直觀,只要通過 ScriptEngineManager
和 ScriptEngine
這兩個類就可以完成最簡單的調用。首先,ScriptEngineManager
實例創建一個 ScriptEngine
實例,然后返回的 ScriptEngine
實例解析 JavaScript 腳本,輸出運行結果。運行這段程序,終端上會輸出“Hello World“。在執行 eval
函數的過程中可能會有 ScriptEngine
異常拋出,引發這個異常被拋出的原因一般是由腳本輸入語法有誤造成的。在對整個 API 有了大致的概念之后,我們就可以開始介紹各個具體的功能了。
![]() ![]() |
![]()
|
Java
腳本 API 通過腳本引擎來運行腳本,整個包的目的就在于統一 Java 平臺與各種腳本引擎的交互方式,制定一個標準,Java
應用程序依照這種標準就能自由的調用各種腳本引擎,而腳本引擎按照這種標準實現,就能被 Java
平臺支持。每一個腳本引擎就是一個腳本解釋器,負責運行腳本,獲取運行結果。ScriptEngine
接口是腳本引擎在 Java 平臺上的抽象,Java 應用程序通過這個接口調用腳本引擎運行腳本程序,并將運行結果返回給虛擬機。
ScriptEngine
接口提供了許多 eval
函數的變體用來運行腳本,這個函數的功能就是獲取腳本輸入,運行腳本,最后返回輸出。清單 1 的例子中直接通過字符串作為 eval
函數的參數讀入腳本程序。除此之外,ScriptEngine
還提供了以一個 java.io.Reader
作為輸入參數的 eval
函數。腳本程序實質上是一些可以用腳本引擎執行的字節流,通過一個 Reader
對象,eval
函數就能從不同的數據源中讀取字節流來運行,這個數據源可以來自內存、文件,甚至直接來自網絡。這樣 Java 應用程序就能直接利用項目原有的腳本資源,無需以 Java 語言對其進行重寫,達到腳本程序與 Java 平臺無縫集成的目的。清單 2 即展示了如何從一個文件中讀取腳本程序并運行,其中如何通過 ScriptEngineManager
獲取 ScriptEngine
實例的細節會在后面詳細介紹。
清單 2. Run Script
public static void main(String[] args) throws Exception {
String script = args[0];
String file = args[1];
FileReader scriptReader = new FileReader(new File(file));
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName(script);
engine.eval(scriptReader);
}
}
通過這種方式,Java 應用程序可以把一些復雜易變的邏輯過程,用更加靈活的弱類型的腳本語言來實現,然后通過 javax.Script
包提供的 API 獲取運行結果,當腳本改變時,只需替換對應的腳本文件,而無需重新編譯構建項目,好處是顯而易見的,即節省了開發時間又提高了開發效率。
EngineScript
接口分別針對 String
輸入和 Reader
輸入提供了三個不同形態的 eval
函數,用于運行腳本:
表 1. ScriptEngine 的 eval 函數
函數 | 描述 |
---|---|
Object eval(Reader reader)
|
從一個 Reader 讀取腳本程序并運行 |
Object eval(Reader reader, Bindings n)
|
以 n 作為腳本級別的綁定,從一個 Reader 讀取腳本程序并運行 |
Object eval(Reader reader, ScriptContext context)
|
在 context 指定的上下文環境下,從一個 Reader 讀取腳本程序并運行 |
Object eval(String script)
|
運行字符串表示的腳本 |
Object eval(String script, Bindings n)
|
以 n 作為腳本級別的綁定,運行字符串表示的腳本 |
Object eval(String script, ScriptContext context)
|
在 context 指定的上下文環境下,運行字符串表示的腳本 |
Java 腳本 API 還為 ScriptEngine
接口提供了一個抽象類 —— AbstractScriptEngine
,這個類提供了其中四個 eval
函數的默認實現,它們分別通過調用 eval(Reader,ScriptContext)
或 eval(String, ScriptContext)
來實現。這樣腳本引擎提供者,只需繼承這個抽象類并提供這兩個函數實現即可。AbstractScriptEngine
有一個保護域 context
用于保存默認上下文的引用,SimpleScriptContext
類被作為 AbstractScriptEngine
的默認上下文。關于上下文環境,將在后面進行詳細介紹。
![]() ![]() |
![]()
|
在前面的兩個例子中,ScriptEngine
實例都是通過調用 ScriptEngineManager
實例的方法返回的,而不是常見的直接通過 new
操作新建一個實例。JSR 223 中引入 ScriptEngineManager
類的意義就在于,將 ScriptEngine
的尋找和創建任務委托給 ScriptEngineManager
實例處理,達到對 API 使用者隱藏這個過程的目的,使 Java 應用程序在無需重新編譯的情況下,支持腳本引擎的動態替換。通過 ScriptEngineManager
類和 ScriptEngineFactory
接口即可完成腳本引擎的發現和創建:
-
ScriptEngineManager
類:自動尋找ScriptEngineFactory
接口的實現類 -
ScriptEngineFactory
接口:創建合適的腳本引擎實例
![]() |
|
ScriptEngineManager
類本身并不知道如何創建一個具體的腳本引擎實例,它會依照 Jar 規約中定義的服務發現機制,查找并創建一個合適的 ScriptEngineFactory
實例,并通過這個工廠類來創建返回實際的腳本引擎。首先,ScriptEngineManager
實例會在當前 classpath 中搜索所有可見的 Jar 包;然后,它會查看每個 Jar 包中的 META -INF/services/ 目錄下的是否包含 javax.script.ScriptEngineFactory
文件,腳本引擎的開發者會提供在 Jar 包中包含一個 ScriptEngineFactory
接口的實現類,這個文件內容即是這個實現類的完整名字;ScriptEngineManager
會根據這個類名,創建一個 ScriptEngineFactory
接口的實例;最后,通過這個工廠類來實例化需要的腳本引擎,返回給用戶。舉例來說,第三方的引擎提供者可能升級更新了新版的腳本引擎實現,通過 ScriptEngineManager
來管理腳本引擎,無需修改一行 Java 代碼就能替換更新腳本引擎。用戶只需在 classpath 中加入新的腳本引擎實現(Jar 包的形式),ScriptEngineManager
就能通過 Service Provider 機制來自動查找到新版本實現,創建并返回對應的腳本引擎實例供調用。圖 2 所示時序圖描述了其中的步驟:
圖 2. 腳本引擎發現機制時序圖

ScriptEngineFactory
接口的實現類被用來描述和實例化 ScriptEngine
接口,每一個實現 ScriptEngine
接口的類會有一個對應的工廠類來描述其元數據(meta
data),ScriptEngineFactory
接口定義了許多函數供 ScriptEngineManager
查詢這些元數據,ScriptEngineManager
會根據這些元數據查找需要的腳本引擎,表 2 列出了可供使用的函數:
表 2. ScriptEngineFactory 提供的查詢函數
函數 | 描述 |
---|---|
String getEngineName()
|
返回腳本引擎的全稱 |
String getEngineVersion()
|
返回腳本引擎的版本信息 |
String getLanguageName()
|
返回腳本引擎所支持的腳本語言的名稱 |
String getLanguageVersion()
|
返回腳本引擎所支持的腳本語言的版本信息 |
List<String> getExtensions()
|
返回一個腳本文件擴展名組成的 List,當前腳本引擎支持解析這些擴展名對應的腳本文件 |
List<String> getMimeTypes()
|
返回一個與當前引擎關聯的所有 mimetype 組成的 List |
List<String> getNames()
|
返回一個當前引擎所有名稱的 List,ScriptEngineManager 可以根據這些名字確定對應的腳本引擎 |
通過 getEngineFactories()
函數,ScriptEngineManager
會返回一個包含當前環境中被發現的所有實現 ScriptEngineFactory
接口的具體類,通過這些工廠類中保存的腳本引擎信息檢索需要的腳本引擎。第三方提供的腳本引擎實現的 Jar 包中除了包含 ScriptEngine
接口的實現類之外,還需要提供 ScriptEngineFactory
接口的實現類,以及一個 javax.script.ScriptEngineFactory
文件用于指明這個工廠類。這樣,Java 平臺就能通過 ScriptEngineManager
尋找到這個工廠類,并通過這個工廠類為用戶提供一個腳本引擎實例。Java SE 6 默認提供了 JavaScirpt 腳本引擎的實現,如果需要支持其他腳本引擎,需要將它們對應的 Jar 包包含在 classpath 中,比如對于前面 清單 2 中的代碼,只需在運行程序前將 Groovy 的腳本引擎添加到 classpath 中,然后運行:
java RunScript groovy run.groovy |
無需修改一行 Java 代碼就能以 Groovy 腳本引擎來運行 Groovy 腳本。在 這里
為 Java SE 6 提供了許多著名腳本語言的腳本引擎對 JSR 223 的支持,這些 Jar 必須和腳本引擎配合使用,使得這些腳本語言能被
Java 平臺支持。到目前為止,它提供了至少 25 種腳本語言的支持,其中包括了 Groovy、Ruby、Python
等當前非常流行的腳本語言。這里需要再次強調的是,負責創建 ScriptEngine
實例的 ScriptEngineFactory
實現類對于用戶來說是不可見的,ScriptEngingeManager
實現負責與其交互,通過它創建腳本引擎。
![]() ![]() |
![]()
|
如
果僅僅是通過腳本引擎運行腳本的話,還無法體現出 Java 腳本 API 的優點,在 JSR 223
中,還為所有的腳本引擎定義了一個簡潔的執行環境。我們都知道,在 Linux 操作系統中可以維護許多環境變量比如 classpath、path
等,不同的 shell 在運行時可以直接使用這些環境變量,它們構成了 shell 腳本的執行環境。在 javax.script
支持的每個腳本引擎也有各自對應的執行的環境,腳本引擎可以共享同樣的環境,也可以有各自不同的上下文。通過腳本運行時的上下文,腳本程序就能自由的和 Java 平臺交互,并充分利用已有的眾多 Java API,真正的站在“巨人”的肩膀上。javax.script.ScriptContext
接口和 javax.script.Bindings
接口定義了腳本引擎的上下文。
-
Bindings 接口:
繼承自 Map,定義了對這些“鍵-值”對的查詢、添加、刪除等 Map 典型操作。
Bingdings
接口實際上是一個存放數據的容器,它的實現類會維護許多“鍵-值”對,它們都通過字符串表示。Java 應用程序和腳本程序通過這些“鍵-值”對交換數據。只要腳本引擎支持,用戶還能直接在Bindings
中放置 Java 對象,腳本引擎通過Bindings
不僅可以存取對象的屬性,還能調用 Java 對象的方法,這種雙向自由的溝通使得二者真正的結合在了一起。 -
ScriptContext 接口:
將
Bindings
和ScriptEngine
聯系在了一起,每一個ScriptEngine
都有一個對應的ScriptContext
,前面提到過通過ScriptEnginFactory
創建腳本引擎除了達到隱藏實現的目的外,還負責為腳本引擎設置合適的上下文。ScriptEngine
通過ScriptContext
實例就能從其內部的Bindings
中獲得需要的屬性值。ScriptContext
接口默認包含了兩個級別的Bindings
實例的引用,分別是全局級別和引擎級別,可以通過GLOBAL_SCOPE
和ENGINE_SCOPE
這兩個類常量來界定區分這兩個Bindings
實例,其中GLOBAL_SCOPE
從創建它的ScriptEngineManager
獲得。顧名思義,全局級別指的是Bindings
里的屬性都是“全局變量”,只要是同一個ScriptEngineMananger
返回的腳本引擎都可以共享這些屬性;對應的,引擎級別的Bindings
里的屬性則是“局部變量”,它們只對同一個引擎實例可見,從而能為不同的引擎設置獨特的環境,通過同一個腳本引擎運行的腳本運行時能共享這些屬性。
ScriptContext
接口定義了下面這些函數來存取數據:
表 3. ScriptContext 存取屬性函數
函數 | 描述 |
---|---|
Object removeAttribute(String name, int scope)
|
從指定的范圍里刪除一個屬性 |
void setAttribute(String name, Object value, int scope)
|
在指定的范圍里設置一個屬性的值 |
Object getAttribute(String name)
|
從上下文的所有范圍內獲取優先級最高的屬性的值 |
Object getAttribute(String name, int scope)
|
從指定的范圍里獲取屬性值 |
ScriptEngineManager
擁有一個全局性的 Bindings
實例,在通過 ScriptEngineFactory
實例創建 ScriptEngine
后,它把自己的這個 Bindings
傳遞給所有它創建的 ScriptEngine
實例,作為 GLOBAL_SCOPE
。同時,每一個 ScriptEngine
實例都對應一個 ScriptContext
實例,這個 ScriptContext
除了從 ScriptEngineManager
那獲得的 GLOBAL_SCOPE
,自己也維護一個 ENGINE_SCOPE
的 Bindings
實例,所有通過這個腳本引擎運行的腳本,都能存取其中的屬性。除了 ScriptContext
可以設置屬性,改變內部的 Bindings
,Java 腳本 API 為 ScriptEngineManager
和 ScriptEngine
也提供了類似的設置屬性和 Bindings
的 API。
圖 3. Bindings 在 Java 腳本 API 中的分布

從 圖 3 中可以看到,共有三個級別的地方可以存取屬性,分別是 ScriptEngineManager
中的 Bindings
,ScriptEngine
實例對應的 ScriptContext
中含有的 Bindings
,以及調用 eval
函數時傳入的 Bingdings
。離函數調用越近,其作用域越小,優先級越高,相當于編程語言中的變量的可見域,即 Object getAttribute(String name)
中提到的優先級。從 清單 3 這個例子中可以看出各個屬性的存取優先級:
清單 3. 上下文屬性的作用域
public class ScopeTest {
public static void main(String[] args) throws Exception {
String script=" println(greeting) ";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
//Attribute from ScriptEngineManager
manager.put("greeting", "Hello from ScriptEngineManager");
engine.eval(script);
//Attribute from ScriptEngine
engine.put("greeting", "Hello from ScriptEngine");
engine.eval(script);
//Attribute from eval method
ScriptContext context = new SimpleScriptContext();
context.setAttribute("greeting", "Hello from eval method",
ScriptContext.ENGINE_SCOPE);
engine.eval(script,context);
}
}
JavaScript 腳本 println(greeting)
在這個程序中被重復調用了三次,由于三次調用的環境不一樣,導致輸出也不一樣,greeting
變量每一次都被優先級更高的也就是距離函數調用越近的值覆蓋。從這個例子同時也演示了如何使用 ScriptContext
和 Bindings
這兩個接口,在例子腳本中并沒有定義 greeting
這個變量,但是腳本通過 Java 腳本 API 能方便的存取 Java 應用程序中的對象,輸出 greeting
相應的值。運行這個程序后,能看到輸出為:
圖 4. 程序 ScopeTest 的輸出

除了能在 Java 平臺與腳本程序之間的提供共享屬性之外,ScriptContext
還允許用戶重定向引擎執行時的輸入輸出流:
表 4. ScriptContext 輸入輸出重定向
函數 | 描述 |
---|---|
void setErrorWriter(Writer writer)
|
重定向錯誤輸出,默認是標準錯誤輸出 |
void setReader(Reader reader)
|
重定向輸入,默認是標準輸入 |
void setWriter(Writer writer)
|
重定向輸出,默認是標準輸出 |
Writer getErrorWriter()
|
獲取當前錯誤輸出字節流 |
Reader getReader()
|
獲取當前輸入流 |
Writer getWriter()
|
獲取當前輸出流 |
清單 4 展示了如何通過 ScriptContext
將其對應的 ScriptEngine
標準輸出重定向到一個 PrintWriter
中,用戶可以通過與這個 PrintWriter
連通的 PrintReader
讀取實際的輸出,使 Java 應用程序能獲取腳本運行輸出,滿足更加多樣的應用需求。
清單 4. 重定向腳本輸出
import javax.script.*;
public class Redirectory {
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
PipedReader pr = new PipedReader();
PipedWriter pw = new PipedWriter(pr);
PrintWriter writer = new PrintWriter(pw);
engine.getContext().setWriter(writer);
String script = "println('Hello from JavaScript')";
engine.eval(script);
BufferedReader br =new BufferedReader(pr);
System.out.println(br.readLine());
}
}
Java 腳本 API 分別為這兩個接口提供了一個簡單的實現供用戶使用。SimpleBindings
通過組合模式實現 Map
接口,它提供了兩個構造函數。無參構造函數在內部構造一個 HashMap
實例來實現 Map
接口要求的功能;同時,SimpleBindings
也提供了一個以 Map
接口作為參數的構造函數,允許任何實現 Map
接口的類作為其組合的實例,以滿足不同的要求。SimpleScriptContext
提供了 ScriptContext
簡單實現。默認情況下,它使用了標準輸入、標準輸出和標準錯誤輸出,同時維護一個 SimpleBindings
作為其引擎級別的 Bindings,它的默認全局級別 Bindings 為空。
![]() ![]() |
![]()
|
在 Java 腳本 API 中還有兩個腳本引擎可以選擇是否實現的接口,這個兩個接口不是強制要求實現的,即并非所有的腳本引擎都能支持這兩個函數,不過 Java SE 6 自帶的 JavaScript 引擎支持這兩個接口。無論如何,這兩個接口提供了非常實用的功能,它們分別是:
- Invocable 接口:允許 Java 平臺調用腳本程序中的函數或方法。
- Compilable 接口:允許 Java 平臺編譯腳本程序,供多次調用。
有時候,用戶可能并不需要運行已有的整個腳本程序,而僅僅需要調用其中的一個過程,或者其中某個對象的方法,這個時候 Invocable
接口就能發揮作用。它提供了兩個函數 invokeFunction
和 invokeMethod
,分別允許 Java 應用程序直接調用腳本中的一個全局性的過程以及對象中的方法,調用后者時,除了指定函數名字和參數外,還需要傳入要調用的對象引用,當然這需要腳本引擎的支持。不僅如此,Invocable
接口還允許 Java 應用程序從這些函數中直接返回一個接口,通過這個接口實例來調用腳本中的函數或方法,從而我們可以從腳本中動態的生成 Java 應用中需要的接口對象。清單 5 演示了如何使用一個 Invocable
接口:
清單 5. 調用腳本中的函數
public class CompilableTest {
public static void main(String[] args) throws ScriptException,
NoSuchMethodException {
String script = " function greeting(message){println (message);}";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
engine.eval(script);
if (engine instanceof Invocable) {
Invocable invocable = (Invocable) engine;
invocable.invokeFunction("greeting", "hi");
// It may through NoSuchMethodException
try {
invocable.invokeFunction("nogreeing");
} catch (NoSuchMethodException e) {
// expected
}
}
}
}
在調用函數前,可以先通過 instanceof
操作判斷腳本引擎是否支持編譯操作,防止類型轉換時拋出運行時異常,需要特別注意的時,如果調用了腳本程序中不存在的函數時,運行時會拋出一個 NoSuchMethodException
的異常,實際開發中應該注意處理這種特殊情況。
一 般來說,腳本語言都是解釋型的,這也是腳本語言區別與編譯語言的一個特點,解釋性意味著腳本隨時可以被運行,開發者可以邊開發邊查看接口,從而省去了編譯 這個環節,提供了開發效率。但是這也是一把雙刃劍,當腳本規模變大,重復解釋一段穩定的代碼又會帶來運行時的開銷。有些腳本引擎支持將腳本運行編譯成某種 中間形式,這取決與腳本語言的性質以及腳本引擎的實現,可以是一些操作碼,甚至是 Java 字節碼文件。實現了這個接口的腳本引擎能把輸入的腳本預編譯并緩存,從而提高多次運行相同腳本的效率。
Java 腳本 API 還為這個中間形式提供了一個專門的類,每次調用 Compilable
接口的編譯函數都會返回一個 CompiledScript
實例。CompiledScript
類被用來保存編譯的結果,從而能重復調用腳本而沒有重復解釋的開銷,實際效率提高的多少取決于中間形式的徹底程度,其中間形式越接近低級語言,提高的效率就越高。每一個 CompiledScript
實例對應于一個腳本引擎實例,一個腳本引擎實例可以含有多個 CompiledScript
(這很容易理解),調用 CompiledScript
的 eval
函數會傳遞給這個關聯的 ScriptEngine 的 eval
函數。關于 CompiledScript
類需要注意的是,它運行時對與之對應的 ScriptEngine 狀態的改變可能會傳遞給下一次調用,造成運行結果的不一致。清單 6 演示了如何使用 Compiable
接口來調用腳本:
清單 6. 編譯腳本
public class CompilableTest {
public static void main(String[] args) throws ScriptException {
String script = " println (greeting); greeting= 'Good Afternoon!' ";
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
engine.put("greeting", "Good Morning!");
if (engine instanceof Compilable) {
Compilable compilable = (Compilable) engine;
CompiledScript compiledScript = compilable.compile(script);
compiledScript.eval();
compiledScript.eval();
}
}
}
與 InovcableTest
類似,也應該先通過 instanceof
操作判斷腳本引擎是否支持編譯操作,防止預料外的異常拋出。并且我們可以發現同一段編譯過的腳本,在第二次運行時 greeting
變量的內容被上一次的運行改變了,導致輸出不一致:
圖 5. 程序 CompilableTest 的輸出

![]() ![]() |
![]()
|
Java
SE 6 還為運行腳本添加了一個專門的工具 —— jrunscript。jrunscript
支持兩種運行方式:一種是交互式,即邊讀取邊解析運行,這種方式使得用戶可以方便調試腳本程序,馬上獲取預期結果;還有一種就是批處理式,即讀取并運行整
個腳本文件。用戶可以把它想象成一個萬能腳本解釋器,即它可以運行任意腳本程序,而且它還是跨平臺的,當然所有這一切都有一個前提,那就是必須告訴它相應
的腳本引擎的位置。默認即支持的腳本是 JavaScript,這意味著用戶可以無需任何設置,通過 jrunscript 在任何支持 Java
的平臺上運行任何 JavaScript 腳本;如果想運行其他腳本,可以通過 -l
指定以何種腳本引擎運行腳本。不過這個工具仍是實驗性質的,不一定會包含在 Java 的后續版本中,無論如何,它仍是一個非常有用的工具。
![]() ![]() |
![]()
|
在 Java 平臺上使用腳本語言編程非常方便,因為 Java 腳本 API 相對其他包要小很多。通過 javax.script
包提供的接口和類我們可以很方便為我們的 Java 應用程序添加對腳本語言的支持。開發者只要遵照 Java 腳本 API
開發應用程序,開發中就無需關注具體的腳本語言細節,應用程序就可以動態支持任何符合 JSR 223 標準的腳本語言,不僅如此,只要按照 JSR
223 標準開發,用戶甚至還能為 Java 平臺提供一個自定義腳本語言的解釋器。在 Java
平臺上運行自己的腳本語言,這對于眾多開發者來說都是非常有誘惑力的。
盡管千里冰封
依然擁有晴空
你我共同品味JAVA的濃香.