java 脚本语言交互_Java学习笔记--脚本语言支持API
Java語言的動(dòng)態(tài)性之腳本語言支持API
隨著Java平臺(tái)的流行,很多的腳本語言(scripting language)都可以運(yùn)行在Java虛擬機(jī)啊上,其中比較流行的有JavaScript、JRuby、Jython和Groovy等。相對(duì)Java語言來說,腳本語言由于其靈活性非常強(qiáng),非常適合在某些情況下使用,比如描述應(yīng)用中復(fù)雜多變的業(yè)務(wù)邏輯,并在應(yīng)用運(yùn)行過程中進(jìn)行動(dòng)態(tài)修改;為應(yīng)用提供一種領(lǐng)域特定語言(Domainspecific Language,DSL),供沒有技術(shù)背景的普通用戶使用;作為應(yīng)用中各個(gè)組件之間的“膠水”,快速進(jìn)行組件之間的整合;快速開發(fā)出應(yīng)用的原型系統(tǒng),從而迅速獲取用戶反饋,并進(jìn)行改進(jìn);幫助開發(fā)人員快速編寫測(cè)試用例等。等于這些場(chǎng)景,如果使用java來開發(fā)則事倍功半。
對(duì)于這些運(yùn)行在Java虛擬機(jī)平臺(tái)上的腳本語言來說,并不需要為她們準(zhǔn)備額外的運(yùn)行環(huán)境,直接復(fù)用已有的Java虛擬機(jī)環(huán)境即可。這就節(jié)省了在運(yùn)行環(huán)境上所需的成本投入。在應(yīng)用開發(fā)中使用腳本語言,實(shí)際上是“多語言開發(fā)”的一種很好的實(shí)踐,即根據(jù)應(yīng)用的需要和語言本身的特性來選擇最合適的變成語言,以快速高效地解決應(yīng)用中的某一部分問題。多種不同語言實(shí)現(xiàn)的組件組合起來,用Java編寫核心業(yè)務(wù)邏輯,用Ruby來進(jìn)行數(shù)據(jù)處理。不同語言編寫的代碼可以同時(shí)運(yùn)行的同一個(gè)Java虛擬機(jī)之上。這些腳本語言和Java語言之間的交互,是由腳本語言支持API來完成的。
1.腳本引擎
一段腳本的執(zhí)行需要由該腳本語言對(duì)應(yīng)的腳本引擎來完成。一個(gè)Java程序可以選擇同時(shí)包含多種腳本語言的執(zhí)行引擎,這完全由程序的需求來決定。程序中所用到的腳本語言,都需要有相應(yīng)的腳本引擎。JSR 233中定義了腳本引擎的注冊(cè)和查找機(jī)制。這對(duì)于腳本引擎的實(shí)現(xiàn)者來說,是需要了解的。而一般的開發(fā)人員只需要了解如何通過腳本引擎管理器來獲取對(duì)應(yīng)語言的腳本引擎,并不需要了解腳本引擎的注冊(cè)機(jī)制。Java SE6中自帶了JavaScript語言的腳本引擎,是基于Mozilla的Rhino來實(shí)現(xiàn)的。對(duì)于其他的腳本語言,則需要下載對(duì)應(yīng)的腳本引擎的庫并放在程序的類路徑中。一般只要放在類路徑中中,腳本引擎就可以被應(yīng)用程序發(fā)現(xiàn)并使用。
首先介紹腳本引擎的一般用法。首先創(chuàng)建一個(gè)腳本引擎管理器javax.script.ScriptEngineManager對(duì)象,再通過管理器來查詢所需的JavaScript腳本引擎,最后通過腳本引擎來執(zhí)行JavaScript代碼。
ScriptEngineManagerDemo
執(zhí)行結(jié)果
上面的代碼中是通過腳本引擎的名字進(jìn)行查找的。實(shí)際上,腳本引擎管理共支持三種查找腳本引擎的方式,分別通過名稱、文件擴(kuò)展名和MIME類型來完成。
2.語言綁定
腳本語言支持API的一個(gè)很大優(yōu)勢(shì)在于它規(guī)范了Java語言與腳本語言之間的交互方式,使Java語言編寫的程序可以與腳本之間進(jìn)行雙向的方法調(diào)用和數(shù)據(jù)傳遞。方法調(diào)用的方式會(huì)在稍后介紹。數(shù)據(jù)傳遞是通過語言綁定對(duì)象來完成的。所謂的綁定對(duì)象就是一個(gè)簡(jiǎn)單的哈希表,用來存放和獲取需要共享的數(shù)據(jù)。所有數(shù)據(jù)都對(duì)應(yīng)這個(gè)哈希表中的一個(gè)條目,是簡(jiǎn)單的名值對(duì)。接口javax.script.Bindings定義了語言綁定對(duì)象的接口,繼承自java.util.Map接口。一個(gè)腳本引擎在執(zhí)行過程中可能會(huì)使用多個(gè)語言綁定對(duì)象。不同語言綁定對(duì)象的作用域不同。在默認(rèn)情況下,腳本引擎會(huì)提供多個(gè)語言綁定對(duì)象,用來存放在執(zhí)行過程中產(chǎn)生全局對(duì)象等。ScriptEngine類提供了put和get方法對(duì)腳本引擎中特定作用域的默認(rèn)語言綁定對(duì)象進(jìn)行操作。程序可以直接使用這個(gè)默認(rèn)的語言綁定對(duì)象,也可以使用自己的語言綁定對(duì)象。在腳本語言的執(zhí)行過程中,可以將語言綁定對(duì)象看成是一個(gè)額外的變量映射表。在解析變量值的時(shí)候,語言綁定對(duì)象中的名稱也會(huì)被考慮在內(nèi)。腳本執(zhí)行過程中產(chǎn)生的全局變量等內(nèi)容,會(huì)出現(xiàn)在語言綁定對(duì)象中。通過這種方式就完成了Java與腳本語言之間的雙向數(shù)據(jù)傳遞。
腳本引擎默認(rèn)的語言綁定對(duì)象的示例
/**
* 腳本引擎默認(rèn)的語言綁定對(duì)象的示例
*/
public static void useDefaultBinding(){
try{
ScriptEngine engine = getJavaScriptEngine();
engine.put("name","Arthur");
engine.eval("var message = 'Hello,' + name;");
engine.eval("print(message);");
Object obj = engine.get("message");
System.out.println(obj);
}catch (Exception e){
System.out.println("異常信息:"+e.getMessage());
}
}
腳本引擎默認(rèn)的語言綁定對(duì)象的示例執(zhí)行結(jié)果
在大多數(shù)情況下,使用ScriptEngine的put和get方法就足夠了。如果僅使用put和get方法,語言綁定對(duì)象本身對(duì)于開發(fā)人員來說是透明的。在某些情況下,需要使用程序自己的語言綁定對(duì)象,比如語言綁定對(duì)象中包含了程序自己獨(dú)有的數(shù)據(jù)。如果希望使用自己的語言綁定對(duì)象,可以調(diào)用腳本引擎的createBindings方法或創(chuàng)建,并傳遞給腳本引擎的eval方法。
自定義語言綁定對(duì)象的示例
/**
* 自定義語言綁定對(duì)象的示例
*/
public static void userCustomBinding(){
try{
ScriptEngine engine = getJavaScriptEngine();
Bindings bindings = new SimpleBindings();
bindings.put("hobby","playe games");
engine.eval("print('I like ' + hobby);",bindings);
}catch(Exception e){
System.out.println("異常信息:"+e.getMessage());
}
}
自定義語言綁定對(duì)象的示例的執(zhí)行結(jié)果
通過eval方法傳遞的語綁定對(duì)象,僅在當(dāng)前eval調(diào)用中生效,并不會(huì)改變引擎默認(rèn)的語言綁定對(duì)象。
3.腳本執(zhí)行上下文
與腳本引擎執(zhí)行相關(guān)的另外一個(gè)重要的接口是javax.script.ScriptContext,其中包含腳本引擎執(zhí)行過程的相關(guān)上下文信息,可以通過與Java EE中servlet規(guī)范中的javax.servlet.ServletContext接口來進(jìn)行類比。腳本引擎通過此上下文對(duì)象獲取與腳本執(zhí)行相關(guān)的信息,也允許開發(fā)人員通過此對(duì)象來配置腳本引擎的行為。該上下文對(duì)象主要包含以下3類信息:
3.1輸入與輸出
首先介紹與腳本輸入和輸出的配置信息,其中包括腳本在執(zhí)行中用來讀取數(shù)據(jù)輸入的java.io.Reader對(duì)象以及輸出正確內(nèi)容和出錯(cuò)信息的java.io.Writer對(duì)象。在默認(rèn)情況下,腳本的輸入輸出都在發(fā)生在標(biāo)準(zhǔn)控制臺(tái)中。
把腳本運(yùn)行時(shí)的輸出寫入到文件中的示例
/**
* 把腳本運(yùn)行時(shí)的輸出寫入到文件中。
*/
public static void scriptToFile(){
try {
ScriptEngine engine = getJavaScriptEngine();
ScriptContext context = engine.getContext();
context.setWriter(new FileWriter("output.txt"));
engine.eval("print('Hello World!');");
} catch (ScriptException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
執(zhí)行結(jié)果
說明
通過setWriter方法把腳本的輸出重定向到一個(gè)文件中。通過ScriptContext的setReader和setErrorWriter方法可以分別設(shè)置腳本執(zhí)行時(shí)的數(shù)據(jù)輸入來源和產(chǎn)生錯(cuò)誤時(shí)出錯(cuò)信息的輸出目的。
3.2自定義屬性
ScriptContext中也有與ServletConext中類似的獲取和設(shè)置屬性的方法,即setAttribute和getAttribute。所不同的是,ScriptContext中的屬性是有作用域之分的。不同作用域的區(qū)別在于查找屬性時(shí)的順序不同。每個(gè)作用域都以一個(gè)對(duì)應(yīng)的整數(shù)表示其查找順序。該整數(shù)值越小,說明查找時(shí)的順序越優(yōu)先。優(yōu)先級(jí)高的作用域中的屬性會(huì)隱藏優(yōu)先級(jí)低的作用域中的同名屬性。因此,設(shè)置屬性時(shí)需要顯式地指定所在地作用域。在獲取屬性地時(shí)候,既可以選擇在指定地作用域中查找,也可以選擇根據(jù)作用域優(yōu)先級(jí)自動(dòng)進(jìn)行查找。
不過腳本執(zhí)行上下文實(shí)現(xiàn)中包含地作用域是固定的,開發(fā)人員不能隨意定義自己的作用域。通過ScriptContext的getScopes方法可以得到所有可用的作用域列表。ScriptContext中預(yù)先定義了兩個(gè)作用域:
常量ScriptContext.ENGINE_SCOPE表示的作用域?qū)?yīng)的是當(dāng)前的腳本引擎。
常量ScriptContext.GLOBAL_SCOPE表示的作用域?qū)?yīng)的是從同一引擎工廠中創(chuàng)建出來的所有腳本引擎對(duì)象。
說明: 前者的優(yōu)先級(jí)較高
作用域影響同名屬性查找示例
/**
* 作用域影響同名屬性查找的示例
*/
public static void scriptContextAttribute(){
try{
ScriptEngine engine = getJavaScriptEngine();
ScriptContext context = engine.getContext();
context.setAttribute("name","Arthur Ming",ScriptContext.GLOBAL_SCOPE);
context.setAttribute("name","明國賓",ScriptContext.ENGINE_SCOPE);
System.out.println(context.getAttribute("name"));
System.out.println(context.getAttribute("name",ScriptContext.GLOBAL_SCOPE));
} catch(Exception e){
System.out.println("異常信息:"+e.getMessage());
}
}
執(zhí)行結(jié)果
3.1語言綁定對(duì)象
腳本執(zhí)行上下文中的最后一類信息是語言綁定對(duì)象。語言綁定對(duì)象也是與作用域相對(duì)應(yīng)的,同樣的作用域優(yōu)先級(jí)順序?qū)φZ言綁定對(duì)象也適用。這樣的優(yōu)先級(jí)順序會(huì)對(duì)腳本執(zhí)行時(shí)的變量解析產(chǎn)生影響。
語言綁定對(duì)象的優(yōu)先級(jí)順序的示例
/**
* 語言綁定對(duì)象的優(yōu)先級(jí)順序的示例
*/
public static void scriptContextBindings(){
try {
ScriptEngine engine = getJavaScriptEngine();
ScriptContext context = engine.getContext();
Bindings binding1 = engine.createBindings();
binding1.put("name","Arthur Ming");
context.setBindings(binding1,ScriptContext.GLOBAL_SCOPE);
Bindings binding2 = engine.createBindings();
binding2.put("name","明國賓");
context.setBindings(binding2,ScriptContext.ENGINE_SCOPE);
engine.eval("print(name)");
} catch (Exception e){
e.printStackTrace();
}
}
執(zhí)行結(jié)果
通過ScriptContext的setBindings方法設(shè)置的語言綁定對(duì)象會(huì)影響到ScriptEngine在執(zhí)行腳本時(shí)變量解析。ScriptEngine的put和get方法所操作的實(shí)際上就是ScriptContext中的作用域?yàn)镋NGINE_SCOPE的語言綁定對(duì)象。
通過腳本執(zhí)行上下文獲取語言綁定對(duì)象的示例
/**
* 通過腳本執(zhí)行上下文獲取語言綁定對(duì)象的示例
*/
public static void useScriptContextValues(){
try{
ScriptEngine engine = getJavaScriptEngine();
ScriptContext context = engine.getContext();
Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
bindings.put("name","Arthur Ming");
engine.eval("print(name)");
} catch (Exception e){
e.printStackTrace();
}
}
執(zhí)行結(jié)果
自定義屬性實(shí)際上也保存在語言綁定對(duì)象中。
自定義屬性保存在語言綁定對(duì)象中示例
/**
* 自定義屬性保存在語言綁定對(duì)象中示例
*/
public static void attributeInBindings(){
try{
ScriptEngine engine = getJavaScriptEngine();
ScriptContext context = engine.getContext();
context.setAttribute("name1","Arthur Ming",ScriptContext.GLOBAL_SCOPE);
context.setAttribute("name2","明國賓",ScriptContext.ENGINE_SCOPE);
engine.eval("print(name1);");
engine.eval("print(name2);");
}catch (Exception e){
e.printStackTrace();
}
}
執(zhí)行結(jié)果
總結(jié)
以上是生活随笔為你收集整理的java 脚本语言交互_Java学习笔记--脚本语言支持API的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新东方在线CFO尹强减持100万股股份
- 下一篇: java美元兑换,(Java实现) 美元