年底Sun 公司發布了 Java Standard Edition (Java SE )的最終正式版代號 Mustang(野馬)跟 Tiger(Java SE )相比Mustang 在性能方面有了不錯的提升與 Tiger 在 API 庫方面的大幅度加強相比雖然 Mustang 在 API 庫方面的新特性顯得不太多但是也提供了許多實用和方便的功能在腳本WebServiceXML編譯器 API數據庫JMX網絡 和 Instrumentation 方面都有不錯的新特性和功能加強
本系列 文章主要介紹 Java SE 在 API 庫方面的部分新特性通過一些例子和講解幫助開發者在編程實踐當中更好的運用 Java SE 提高開發效率本文是系列文章的第 篇介紹了 Java SE 在腳本編程方面的新特性
Java 腳本 API 概述
Java SE 引入了對 Java Specification Request(JSR) 的支持JSR 旨在定義一個統一的規范使得 Java 應用程序可以通過一套固定的接口與各種腳本引擎交互從而達到在 Java 平台上調用各種腳本語言的目的javaxscript 包定義了這些接口即 Java 腳本編程 APIJava 腳本 API 的目標與 Apache 項目 Bean Script Framework(BSF)類似通過它 Java 應用程序就能通過虛擬機調用各種腳本同時腳本語言也能訪問應用程序中的 Java 對象和方法Java 腳本 API 是連通 Java 平台和腳本語言的橋梁首先通過它為數眾多的現有 Java 庫就能被各種腳本語言所利用節省了開發成本縮短了開發周期其次可以把一些復雜異變的業務邏輯交給腳本語言處理這又大大提高了開發效率
在 javaxscript 包中定義的實現類並不多主要是一些接口和對應的抽象類圖 顯示了其中包含的各個接口和類
圖 javaxscript 包概況
![](http://tw.wingwit.com/Article/UploadFiles/201311/2013111511451368.jpg)
這個包的具體實現類少的根本原因是這個包只是定義了一個編程接口的框架規范至於對如何解析運行具體的腳本語言還需要由第三方提供實現雖然這些腳本引擎的實現各不相同但是對於 Java 腳本 API 的使用者來說這些具體的實現被很好的隔離隱藏了Java 腳本 API 為開發者提供了如下功能
獲取腳本程序輸入通過腳本引擎運行腳本並返回運行結果這是最核心的接口
發現腳本引擎查詢腳本引擎信息
通過腳本引擎的運行上下文在腳本和 Java 平台間交換數據
通過 Java 應用程序調用腳本函數
在詳細介紹這四個功能之前我們先通過一個簡單的例子來展示如何通過 Java 語言來運行腳本程序這裡仍然以經典的Hello World開始
清單 Hello World
import javaxscript*;
public class HelloWorld {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = managergetEngineByName(JavaScript);
engineeval(print (Hello World));
}
}
這個例子非常直觀只要通過 ScriptEngineManager 和 ScriptEngine 這兩個類就可以完成最簡單的調用首先ScriptEngineManager 實例創建一個 ScriptEngine 實例然後返回的 ScriptEngine 實例解析 JavaScript 腳本輸出運行結果運行這段程序終端上會輸出Hello World在執行 eval 函數的過程中可能會有 ScriptEngine 異常拋出引發這個異常被拋出的原因一般是由腳本輸入語法有誤造成的在對整個 API 有了大致的概念之後我們就可以開始介紹各個具體的功能了
使用腳本引擎運行腳本
Java 腳本 API 通過腳本引擎來運行腳本整個包的目的就在於統一 Java 平台與各種腳本引擎的交互方式制定一個標准Java 應用程序依照這種標准就能自由的調用各種腳本引擎而腳本引擎按照這種標准實現就能被 Java 平台支持每一個腳本引擎就是一個腳本解釋器負責運行腳本獲取運行結果ScriptEngine 接口是腳本引擎在 Java 平台上的抽象Java 應用程序通過這個接口調用腳本引擎運行腳本程序並將運行結果返回給虛擬機
ScriptEngine 接口提供了許多 eval 函數的變體用來運行腳本這個函數的功能就是獲取腳本輸入運行腳本最後返回輸出清單 的例子中直接通過字符串作為 eval 函數的參數讀入腳本程序除此之外ScriptEngine 還提供了以一個 javaioReader 作為輸入參數的 eval 函數腳本程序實質上是一些可以用腳本引擎執行的字節流通過一個 Reader 對象eval 函數就能從不同的數據源中讀取字節流來運行這個數據源可以來自內存文件甚至直接來自網絡這樣 Java 應用程序就能直接利用項目原有的腳本資源無需以 Java 語言對其進行重寫達到腳本程序與 Java 平台無縫集成的目的清單 即展示了如何從一個文件中讀取腳本程序並運行其中如何通過 ScriptEngineManager 獲取 ScriptEngine 實例的細節會在後面詳細介紹
清單 Run Script
public class RunScript {
public static void main(String[] args) throws Exception {
String script = args[];
String file = args[];
FileReader scriptReader = new FileReader(new File(file));
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = managergetEngineByName(script);
engineeval(scriptReader);
}
}
清單 代碼從命令行分別獲取腳本名稱和腳本文件名程序通過腳本名稱創建對應的腳本引擎實例通過腳本名稱指定的腳本文件名讀入腳本程序運行運行下面這個命令就能在 Java 平台上運行所有的 JavaScript 腳本
java RunScript javascript runjs
通過這種方式Java 應用程序可以把一些復雜易變的邏輯過程用更加靈活的弱類型的腳本語言來實現然後通過 javaxScript 包提供的 API 獲取運行結果當腳本改變時只需替換對應的腳本文件而無需重新編譯構建項目好處是顯而易見的即節省了開發時間又提高了開發效率
EngineScript 接口分別針對 String 輸入和 Reader 輸入提供了三個不同形態的 eval 函數用於運行腳本
表 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(ReaderScriptContext) 或 eval(String ScriptContext) 來實現這樣腳本引擎提供者只需繼承這個抽象類並提供這兩個函數實現即可AbstractScriptEngine 有一個保護域 context 用於保存默認上下文的引用SimpleScriptContext 類被作為 AbstractScriptEngine 的默認上下文關於上下文環境將在後面進行詳細介紹
發現和創建腳本引擎
在前面的兩個例子中ScriptEngine 實例都是通過調用 ScriptEngineManager 實例的方法返回的而不是常見的直接通過 new 操作新建一個實例JSR 中引入 ScriptEngineManager 類的意義就在於將 ScriptEngine 的尋找和創建任務委托給 ScriptEngineManager 實例處理達到對 API 使用者隱藏這個過程的目的使 Java 應用程序在無需重新編譯的情況下支持腳本引擎的動態替換通過 ScriptEngineManager 類和 ScriptEngineFactory 接口即可完成腳本引擎的發現和創建
ScriptEngineManager 類
自動尋找 ScriptEngineFactory 接口的實現類
ScriptEngineFactory 接口
創建合適的腳本引擎實例
ScriptEngineManager 類本身並不知道如何創建一個具體的腳本引擎實例它會依照 Jar 規約中定義的服務發現機制查找並創建一個合適的 ScriptEngineFactory 實例並通過這個工廠類來創建返回實際的腳本引擎首先ScriptEngineManager 實例會在當前 classpath 中搜索所有可見的 Jar 包然後它會查看每個 Jar 包中的 META INF/services/ 目錄下的是否包含 javaxscriptScriptEngineFactory 文件腳本引擎的開發者會提供在 Jar 包中包含一個 ScriptEngineFactory 接口的實現類這個文件內容即是這個實現類的完整名字ScriptEngineManager 會根據這個類名創建一個 ScriptEngineFactory 接口的實例最後通過這個工廠類來實例化需要的腳本引擎返回給用戶舉例來說第三方的引擎提供者可能升級更新了新版的腳本引擎實現通過 ScriptEngineManager 來管理腳本引擎無需修改一行 Java 代碼就能替換更新腳本引擎用戶只需在 classpath 中加入新的腳本引擎實現(Jar 包的形式)ScriptEngineManager 就能通過 Service Provider 機制來自動查找到新版本實現創建並返回對應的腳本引擎實例供調用圖 所示時序圖描述了其中的步驟
圖 腳本引擎發現機制時序圖
![](http://tw.wingwit.com/Article/UploadFiles/201311/2013111511451310.jpg)
ScriptEngineFactory 接口的實現類被用來描述和實例化 ScriptEngine 接口每一個實現 ScriptEngine 接口的類會有一個對應的工廠類來描述其元數據(meta data)ScriptEngineFactory 接口定義了許多函數供 ScriptEngineManager 查詢這些元數據ScriptEngineManager 會根據這些元數據查找需要的腳本引擎表 列出了可供使用的函數
表 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 接口的實現類以及一個 javaxscriptScriptEngineFactory 文件用於指明這個工廠類這樣Java 平台就能通過 ScriptEngineManager 尋找到這個工廠類並通過這個工廠類為用戶提供一個腳本引擎實例Java SE 默認提供了 JavaScirpt 腳本引擎的實現如果需要支持其他腳本引擎需要將它們對應的 Jar 包包含在 classpath 中比如對於前面 清單 中的代碼只需在運行程序前將 Groovy 的腳本引擎添加到 classpath 中然後運行
java RunScript groovy rungroovy
無需修改一行 Java 代碼就能以 Groovy 腳本引擎來運行 Groovy 腳本在 這裡 為 Java SE 提供了許多著名腳本語言的腳本引擎對 JSR 的支持這些 Jar 必須和腳本引擎配合使用使得這些腳本語言能被 Java 平台支持到目前為止它提供了至少 種腳本語言的支持其中包括了 GroovyRubyPython 等當前非常流行的腳本語言這裡需要再次強調的是負責創建 ScriptEngine 實例的 ScriptEngineFactory 實現類對於用戶來說是不可見的ScriptEngingeManager 實現負責與其交互通過它創建腳本引擎
腳本引擎的運行上下文
如果僅僅是通過腳本引擎運行腳本的話還無法體現出 Java 腳本 API 的優點在 JSR 中還為所有的腳本引擎定義了一個簡潔的執行環境我們都知道在 Linux 操作系統中可以維護許多環境變量比如 classpathpath 等不同的 shell 在運行時可以直接使用這些環境變量它們構成了 shell 腳本的執行環境在 javaxscript 支持的每個腳本引擎也有各自對應的執行的環境腳本引擎可以共享同樣的環境也可以有各自不同的上下文通過腳本運行時的上下文腳本程序就能自由的和 Java 平台交互並充分利用已有的眾多 Java API真正的站在巨人的肩膀上javaxscriptScriptContext 接口和 javaxscriptBindings 接口定義了腳本引擎的上下文
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 接口定義了下面這些函數來存取數據
表 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 可以設置屬性改變內部的 BindingsJava 腳本 API 為 ScriptEngineManager 和 ScriptEngine 也提供了類似的設置屬性和 Bindings 的 API
圖 Bindings 在 Java 腳本 API 中的分布
![](http://tw.wingwit.com/Article/UploadFiles/201311/2013111511451394.jpg)
從 圖 中可以看到共有三個級別的地方可以存取屬性分別是 ScriptEngineManager 中的 BindingsScriptEngine 實例對應的 ScriptContext 中含有的 Bindings以及調用 eval 函數時傳入的 Bingdings離函數調用越近其作用域越小優先級越高相當於編程語言中的變量的可見域即 Object getAttribute(String name) 中提到的優先級從 清單 這個例子中可以看出各個屬性的存取優先級
清單 上下文屬性的作用域
import javaxscript*;
public class ScopeTest {
public static void main(String[] args) throws Exception {
String script= println(greeting) ;
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = managergetEngineByName(javascript);
//Attribute from ScriptEngineManager
managerput(greeting Hello from ScriptEngineManager);
engineeval(script);
//Attribute from ScriptEngine
engineput(greeting Hello from ScriptEngine);
engineeval(script);
//Attribute from eval method
ScriptContext context = new SimpleScriptContext();
contextsetAttribute(greeting Hello from eval method
ScriptContextENGINE_SCOPE);
engineeval(scriptcontext);
}
}
JavaScript 腳本 println(greeting) 在這個程序中被重復調用了三次由於三次調用的環境不一樣導致輸出也不一樣greeting 變量每一次都被優先級更高的也就是距離函數調用越近的值覆蓋從這個例子同時也演示了如何使用 ScriptContext 和 Bindings 這兩個接口在例子腳本中並沒有定義 greeting 這個變量但是腳本通過 Java 腳本 API 能方便的存取 Java 應用程序中的對象輸出 greeting 相應的值運行這個程序後能看到輸出為
圖 程序 ScopeTest 的輸出
![](http://tw.wingwit.com/Article/UploadFiles/201311/2013111511451352.jpg)
除了能在 Java 平台與腳本程序之間的提供共享屬性之外ScriptContext 還允許用戶重定向引擎執行時的輸入輸出流
表 ScriptContext 輸入輸出重定向
函數 |
描述 |
void setErrorWriter(Writer writer)
重定向錯誤輸出
默認是標准錯誤輸出
void setReader(Reader reader)
重定向輸入
默認是標准輸入
void setWriter(Writer writer)
重定向輸出
默認是標准輸出
Writer getErrorWriter()
獲取當前錯誤輸出字節流
Reader getReader()
獲取當前輸入流
Writer getWriter()
獲取當前輸出流
清單 展示了如何通過 ScriptContext 將其對應的 ScriptEngine 標准輸出重定向到一個 PrintWriter 中用戶可以通過與這個 PrintWriter 連通的 PrintReader 讀取實際的輸出使 Java 應用程序能獲取腳本運行輸出滿足更加多樣的應用需求
清單 重定向腳本輸出
import javaio*;
import javaxscript*;
public class Redirectory {
public static void main(String[] args) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = managergetEngineByName(javascript);
PipedReader pr = new PipedReader();
PipedWriter pw = new PipedWriter(pr);
PrintWriter writer = new PrintWriter(pw);
enginegetContext()setWriter(writer);
String script = println(Hello from JavaScript);
engineeval(script);
BufferedReader br =new BufferedReader(pr);
Systemoutprintln(brreadLine());
}
}
Java 腳本 API 分別為這兩個接口提供了一個簡單的實現供用戶使用SimpleBindings 通過組合模式實現 Map 接口它提供了兩個構造函數無參構造函數在內部構造一個 HashMap 實例來實現 Map 接口要求的功能同時SimpleBindings 也提供了一個以 Map 接口作為參數的構造函數允許任何實現 Map 接口的類作為其組合的實例以滿足不同的要求SimpleScriptContext 提供了 ScriptContext 簡單實現默認情況下它使用了標准輸入標准輸出和標准錯誤輸出同時維護一個 SimpleBindings 作為其引擎級別的 Bindings它的默認全局級別 Bindings 為空
腳本引擎可選的接口
在 Java 腳本 API 中還有兩個腳本引擎可以選擇是否實現的接口這個兩個接口不是強制要求實現的即並非所有的腳本引擎都能支持這兩個函數不過 Java SE 自帶的 JavaScript 引擎支持這兩個接口無論如何這兩個接口提供了非常實用的功能它們分別是
Invocable 接口允許 Java 平台調用腳本程序中的函數或方法
Compilable 接口允許 Java 平台編譯腳本程序
供多次調用
Invocable 接口
有時候用戶可能並不需要運行已有的整個腳本程序而僅僅需要調用其中的一個過程或者其中某個對象的方法這個時候 Invocable 接口就能發揮作用它提供了兩個函數 invokeFunction 和 invokeMethod分別允許 Java 應用程序直接調用腳本中的一個全局性的過程以及對象中的方法調用後者時除了指定函數名字和參數外還需要傳入要調用的對象引用當然這需要腳本引擎的支持不僅如此Invocable 接口還允許 Java 應用程序從這些函數中直接返回一個接口通過這個接口實例來調用腳本中的函數或方法從而我們可以從腳本中動態的生成 Java 應用中需要的接口對象清單 演示了如何使用一個 Invocable 接口
清單 調用腳本中的函數
import javaxscript*;
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 = managergetEngineByName(javascript);
engineeval(script);
if (engine instanceof Invocable) {
Invocable invocable = (Invocable) engine;
invocableinvokeFunction(greeting hi);
// It may through NoSuchMethodException
try {
invocableinvokeFunction(nogreeing);
} catch (NoSuchMethodException e) {
// expected
}
}
}
}
在調用函數前可以先通過 instanceof 操作判斷腳本引擎是否支持編譯操作防止類型轉換時拋出運行時異常需要特別注意的時如果調用了腳本程序中不存在的函數時運行時會拋出一個 NoSuchMethodException 的異常實際開發中應該注意處理這種特殊情況
Compilable 接口
一般來說腳本語言都是解釋型的這也是腳本語言區別與編譯語言的一個特點解釋性意味著腳本隨時可以被運行開發者可以邊開發邊查看接口從而省去了編譯這個環節提供了開發效率但是這也是一把雙刃劍當腳本規模變大重復解釋一段穩定的代碼又會帶來運行時的開銷有些腳本引擎支持將腳本運行編譯成某種中間形式這取決與腳本語言的性質以及腳本引擎的實現可以是一些操作碼甚至是 Java 字節碼文件實現了這個接口的腳本引擎能把輸入的腳本預編譯並緩存從而提高多次運行相同腳本的效率
Java 腳本 API 還為這個中間形式提供了一個專門的類每次調用 Compilable 接口的編譯函數都會返回一個 CompiledScript 實例CompiledScript 類被用來保存編譯的結果從而能重復調用腳本而沒有重復解釋的開銷實際效率提高的多少取決於中間形式的徹底程度其中間形式越接近低級語言提高的效率就越高每一個 CompiledScript 實例對應於一個腳本引擎實例一個腳本引擎實例可以含有多個 CompiledScript(這很容易理解)調用 CompiledScript 的 eval 函數會傳遞給這個關聯的 ScriptEngine 的 eval 函數關於 CompiledScript 類需要注意的是它運行時對與之對應的 ScriptEngine 狀態的改變可能會傳遞給下一次調用造成運行結果的不一致清單 演示了如何使用 Compiable 接口來調用腳本
清單 編譯腳本
import javaxscript*;
public class CompilableTest {
public static void main(String[] args) throws ScriptException {
String script = println (greeting); greeting= Good Afternoon! ;
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = managergetEngineByName(javascript);
engineput(greeting Good Morning!);
if (engine instanceof Compilable) {
Compilable compilable = (Compilable) engine;
CompiledScript compiledScript = pile(script);
compiledScripteval();
compiledScripteval();
}
}
}
與 InovcableTest 類似也應該先通過 instanceof 操作判斷腳本引擎是否支持編譯操作防止預料外的異常拋出並且我們可以發現同一段編譯過的腳本在第二次運行時 greeting 變量的內容被上一次的運行改變了導致輸出不一致
圖 程序 CompilableTest 的輸出
![](http://tw.wingwit.com/Article/UploadFiles/201311/2013111511451327.jpg)
jrunscript 工具
Java SE 還為運行腳本添加了一個專門的工具 —— jrunscriptjrunscript 支持兩種運行方式一種是交互式即邊讀取邊解析運行這種方式使得用戶可以方便調試腳本程序馬上獲取預期結果還有一種就是批處理式即讀取並運行整個腳本文件用戶可以把它想象成一個萬能腳本解釋器即它可以運行任意腳本程序而且它還是跨平台的當然所有這一切都有一個前提那就是必須告訴它相應的腳本引擎的位置默認即支持的腳本是 JavaScript這意味著用戶可以無需任何設置通過 jrunscript 在任何支持 Java 的平台上運行任何 JavaScript 腳本如果想運行其他腳本可以通過 l 指定以何種腳本引擎運行腳本不過這個工具仍是實驗性質的不一定會包含在 Java 的後續版本中無論如何它仍是一個非常有用的工具
結束語
在 Java 平台上使用腳本語言編程非常方便因為 Java 腳本 API 相對其他包要小很多通過 javaxscript 包提供的接口和類我們可以很方便為我們的 Java 應用程序添加對腳本語言的支持開發者只要遵照 Java 腳本 API 開發應用程序開發中就無需關注具體的腳本語言細節應用程序就可以動態支持任何符合 JSR 標准的腳本語言不僅如此只要按照 JSR 標准開發用戶甚至還能為 Java 平台提供一個自定義腳本語言的解釋器在 Java 平台上運行自己的腳本語言這對於眾多開發者來說都是非常有誘惑力的
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19553.html