电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

為Java創(chuàng)建你自己的腳本語(yǔ)言-JSR 223介紹

瀏覽:140日期:2024-06-05 15:10:43
內(nèi)容: 摘要即將發(fā)布的Java6.0包含了Java平臺(tái)腳本(JSR 223)的實(shí)現(xiàn)。這個(gè)JSR關(guān)注于程序設(shè)計(jì)語(yǔ)言以及他們與Java的整合。本文通過(guò)一個(gè)簡(jiǎn)單的“Boolean語(yǔ)言的實(shí)現(xiàn)展示了JSR 223的能力和潛力。通過(guò)這個(gè)例子,你將看到如何使用Scripting API(javax.script.*)編寫(xiě)程序,如何打包并發(fā)布一個(gè)符合腳本引擎發(fā)現(xiàn)機(jī)制的語(yǔ)言實(shí)現(xiàn),以及如何使你的腳本引擎對(duì)JSR 223是可編譯和可調(diào)用的。在Java平臺(tái)腳本(JSR 223)——以及他的前任BSF(Bean Scripting Framework)——之前,已經(jīng)有很多種語(yǔ)言可以與Java交互。其中一些可以接受一段Java程序的文本代碼作為輸入,然后將代碼的執(zhí)行結(jié)果返回給Java程序。而另外一些可以保持Java程序里的對(duì)象的引用,并可以執(zhí)行這個(gè)對(duì)象的方法,或者創(chuàng)建一個(gè)新的Java Class的實(shí)例。由于每個(gè)語(yǔ)言都有自己的與Java交互的方法,開(kāi)發(fā)人員如果想要在他們的Java程序中使用腳本引擎就必須學(xué)習(xí)每個(gè)腳本引擎特殊的編程接口。為了解決這個(gè)問(wèn)題,JSR 223定義了一個(gè)約定,所有遵循這個(gè)規(guī)范的腳本引擎都必須遵守這個(gè)約定。這個(gè)約定由一組Java接口和類(lèi)、以及一個(gè)打包和部署腳本引擎的機(jī)制組成。當(dāng)使用遵循JSR 223的腳本引擎時(shí),只需要使用標(biāo)準(zhǔn)定義的一組接口。由于腳本引擎的具體實(shí)現(xiàn)會(huì)被良好地封裝,你根本不需要考慮他們。JSR 223不僅使腳本引擎使用更簡(jiǎn)單,而且也使腳本引擎的開(kāi)發(fā)更簡(jiǎn)單。如果你設(shè)計(jì)實(shí)現(xiàn)了一個(gè)程序語(yǔ)言,只需要實(shí)現(xiàn)JSR 223的接口來(lái)包裝(wrap)你的腳本引擎,就可以使你的腳本引擎更容易使用并擁有更多的使用者。在我們看JSR 223的接口和本文對(duì)他們的實(shí)現(xiàn)之前,我先要指出:雖然JSR 223的名稱(chēng)和本文的標(biāo)題里都含有“腳本這個(gè)詞,但是并不意味著會(huì)限制在可以使用JSR 223進(jìn)行整合的語(yǔ)言。你可以使用任何你喜歡的語(yǔ)言,并且用一個(gè)遵守JSR 223約定的層包裝它。這個(gè)語(yǔ)言可以是面向?qū)ο蟮摹⒑瘮?shù)的、或者符合任何編程范型的程序語(yǔ)言。他可以是強(qiáng)類(lèi)型、弱類(lèi)型或者根本沒(méi)有類(lèi)型限制。事實(shí)上,在寫(xiě)這篇文章前,我已經(jīng)為Scheme(一個(gè)弱類(lèi)型的函數(shù)程序語(yǔ)言)實(shí)現(xiàn)了一個(gè)遵循JSR 223的包裝器,并已經(jīng)放到了SourceForge上。在這篇文章里,我們使用一個(gè)更簡(jiǎn)單的語(yǔ)言,這樣我們就可以集中精力于JSR 223,而不用費(fèi)神于語(yǔ)言的細(xì)節(jié)。不用擔(dān)心你是否有自己創(chuàng)建一個(gè)程序語(yǔ)言的經(jīng)歷。這篇文章不討論程序語(yǔ)言,只是討論JSR 223定義的程序語(yǔ)言和Java之間需要遵循的約定。版權(quán)聲明:任何獲得Matrix授權(quán)的網(wǎng)站,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必保留以下作者信息和鏈接作者:Chaur Wu;niuji原文:http://www.javaworld.com/javaworld/jw-04-2006/jw-0424-scripting.htmlMatrix:http://www.matrix.org.cn/resource/article/44/44604_JSR+223.html關(guān)鍵字:JSR 223BoolScript引擎圖一顯示了我們的示例的各個(gè)部分以及他們是如何相互關(guān)聯(lián)的。這篇文章里的示例定義了一個(gè)簡(jiǎn)單的語(yǔ)言,我稱(chēng)之為BoolScript。我稱(chēng)編譯執(zhí)行BoolScript代碼的程序?yàn)锽oolScript引擎。除了編譯和執(zhí)行BoolScript代碼,BoolScript引擎還實(shí)現(xiàn)了JSR 223的約定,是一個(gè)符合JSR 223規(guī)范的腳本引擎。如圖所示,Boolscript引擎的代碼打包在boolscript.jar中。 圖一:BoolScript概覽。在這篇文章里,當(dāng)我提到JSR 223時(shí)都是指JSR 223的規(guī)范,JSR 223框架就是指這個(gè)規(guī)范的實(shí)現(xiàn)。這篇文章里使用的JSR 223框架已經(jīng)包含于Java Standard Edition 6.0中(Java SE是sun的J2SE新名字)。我們的例子里包含了一個(gè)使用BoolScript引擎的Java程序,代碼詳見(jiàn)BoolScriptHostApp.java文件。注意圖一展示了Java程序總是通過(guò)JSR 223框架間接的和腳本引擎打交道。你需要Java SE 6.0 beta和這篇文章的二進(jìn)制文件來(lái)運(yùn)行這個(gè)示例。我使用的Java SE 6.0的版本是build 77。你可以在java.net下載,你也可以使用Sun Developer Network提供的Java SE 6.0。示例代碼在資源中提供下載,其中包含了以下文件:+BoolScriptEngine-Source.zip BoolScript引擎的源代碼+BoolScriptHostExample-Source.zip Java示例程序源代碼+BoolScriptHostExample.zip BoolScript引擎和Java示例程序的二進(jìn)制代碼示例程序是BoolScriptHostExample.zip 中的BoolScriptHostApp.class ,解壓縮到任意文件夾執(zhí)行即可。這個(gè)zip文件里還包含了3個(gè)jar文件,執(zhí)行時(shí)需要將他們加到Java的classpath中。具體可參照run.bat文件里的代碼,這個(gè)文件也包含在BoolScriptHostExample.zip 文件里。示例執(zhí)行產(chǎn)生如下輸出: Mozilla RhinoBool Script Engineanswer of boolean expression is: falseanswer of boolean expression is: trueanswer of boolean expression is: false BoolScript 語(yǔ)言在深入JSR 223的細(xì)節(jié)前,我們先快速地了解一下BoolScript語(yǔ)言。BoolScript非常簡(jiǎn)單,他唯一能做的就是計(jì)算布爾表達(dá)式的值。下面是BoolScript代碼的例子:(True | False) & True(True & x) | y可以看到,BoolScript支持兩個(gè)操作符:&(邏輯與)和|(邏輯或)。BoolScript還支持三個(gè)操作數(shù):True、False和變量,變量的值只能是True或False。腳本引擎發(fā)現(xiàn)機(jī)制為了看清楚JSR 223框架在Java程序和腳本引擎間做了哪些工作,我們先假設(shè)你想要在你的程序里使用一個(gè)腳本引擎。首先,你需要?jiǎng)?chuàng)建腳本引擎的實(shí)例;然后,需要將腳本代碼傳給引擎,讓引擎求值(或者編譯這段腳本代碼供以后執(zhí)行)。我們仔細(xì)看下這些步驟,記住:不論我們做什么,我們只能通過(guò)JSR 223框架使用腳本。創(chuàng)建腳本引擎的實(shí)例前我們首先要?jiǎng)?chuàng)建javax.script.ScriptEngineManager的實(shí)例,然后用這個(gè)實(shí)例查詢腳本引擎的實(shí)例。你可以根據(jù)腳本引擎的名字、MIME類(lèi)型或文件擴(kuò)展名查詢引擎實(shí)例。例如我們的BoolScript代碼保存文件是*.bool,那么文件擴(kuò)展名就是bool。下面的代碼演示了如何使用擴(kuò)展名查詢腳本引擎實(shí)例。ScriptEngineManager engineMgr = new ScriptEngineManager();ScriptEngine bsEngine = engineMgr.getEngineByExtension('bool');但是我們?cè)谀闹付ㄎ覀兊哪_本引擎的名稱(chēng)、MIME類(lèi)型和文件擴(kuò)展名呢?我們使用了BoolScriptEngineFactory類(lèi)來(lái)指定這些屬性。這個(gè)類(lèi)實(shí)現(xiàn)了javax.script.ScriptEngineFactory接口的getExtensions()、getMimeTypes()、和 getNames()方法。我們?cè)谶@幾個(gè)方法里聲明了BoolScript引擎的名稱(chēng)、MIME類(lèi)型和文件擴(kuò)展名。下面是BoolScriptEngineFactory的getExtensions()方法:public List getExtensions() { ArrayList extList = new ArrayList(); extList.add('bool'); return extList;}你可能會(huì)奇怪為什么使用ScriptEngineManager創(chuàng)建BoolScriptEngine的實(shí)例,而不是用下面的方法直接創(chuàng)建:ScriptEngine bsEngine = new BoolScriptEngine();當(dāng)然,你可以用這種方法創(chuàng)建。事實(shí)上,我在開(kāi)發(fā)示例代碼的時(shí)候?yàn)榱藴y(cè)試也這樣使用過(guò)。直接創(chuàng)建腳本引擎實(shí)例在測(cè)試的時(shí)候是可以的,但在實(shí)際運(yùn)行環(huán)境中,這樣做違反了必須通過(guò)JSR 223框架操作腳本引擎的規(guī)定,破壞了JSR 223隱藏腳本引擎信息的目的。JSR 223通過(guò)使用工廠方法(Factory Method)模式隱藏腳本引擎的詳細(xì)信息,從而達(dá)到將腳本引擎從Java程序中解耦的目的。直接創(chuàng)建腳本引擎的另一個(gè)問(wèn)題是略過(guò)了ScriptEngineManager可能會(huì)對(duì)腳本引擎實(shí)例做的初始化工作。接下來(lái)我們就會(huì)看到ScriptEngineManager做的這種工作。ScriptEngineManager是如何根據(jù)bool查找BoolScriptEngine并創(chuàng)建他的實(shí)例的呢?答案就是JSR 223里的腳本引擎發(fā)現(xiàn)機(jī)制。在后面對(duì)這個(gè)機(jī)制的討論過(guò)程中,你將看到ScriptEngineManager會(huì)對(duì)腳本引擎做哪些初始化工作,還有他為什么要做這些工作。根據(jù)腳本引擎發(fā)現(xiàn)機(jī)制,一個(gè)腳本引擎的提供者在打包腳本引擎實(shí)現(xiàn)的類(lèi)文件的時(shí)候還需要打包一個(gè)附加的文件到j(luò)ar文件中。這個(gè)文件必須放在jar文件的META-INF/services目錄下面,而且名稱(chēng)必須是javax.script.ScriptEngineFactory。打開(kāi)boolcripts.jar你就可以看到這樣的目錄結(jié)構(gòu)。文件META-INF/services/javax.script.ScriptEngineFactory的內(nèi)容必須包含實(shí)現(xiàn)了ScriptEngineFactory的類(lèi)的全名。在我們的例子中只有一個(gè)這樣的類(lèi),我們文件內(nèi)容如下:net.sf.model4lang.boolscript.engine.BoolScriptEngineFactory當(dāng)一個(gè)腳本引擎提供者將他/她的腳本引擎打包成jar文件并發(fā)布后,用戶只需要將這個(gè)jar文件放入Java的classpath里就可以完成安裝。圖二展示了Java程序通過(guò)JSR 223框架發(fā)現(xiàn)腳步引擎時(shí)發(fā)生的事件。 圖二 Java程序如何發(fā)現(xiàn)腳本引擎當(dāng)使用名字、MIME類(lèi)型或文件擴(kuò)展名查詢指定的腳本引擎時(shí),ScriptEngineManager將遍歷classpath中所有的的ScriptEngineFactory類(lèi)。如果找到符合的,ScriptEngineManager就會(huì)創(chuàng)建這個(gè)引擎工廠的實(shí)例,然后用這個(gè)工廠實(shí)例創(chuàng)建腳本引擎的實(shí)例。腳本引擎工廠使用getScriptEngine()創(chuàng)建腳本引擎,腳本引擎提供者需要實(shí)現(xiàn)這個(gè)方法。你可以看下BoolScriptEngineFactory的代碼,其中g(shù)etScriptEngine()的實(shí)現(xiàn)如下:public ScriptEngine getScriptEngine() { return new BoolScriptEngine();}這個(gè)方法很簡(jiǎn)單,只是創(chuàng)建了一個(gè)腳本引擎的實(shí)例并將這個(gè)實(shí)例返回給ScriptEngineManager(或者任何調(diào)用這個(gè)方法的類(lèi))。我們感興趣的是在ScriptEngineManager得到這個(gè)實(shí)例后,在將這個(gè)實(shí)例返回給Java程序前,ScriptEngineManager為了初始化這個(gè)引擎而調(diào)用的setBindings()方法。這時(shí)我們需要了解JSR 223的一個(gè)核心概念:Java綁定。在我解釋了綁定、范圍和上下文的概念和構(gòu)造后,你就能明白setBindings()為腳本引擎做了哪些初始化工作。綁定、范圍、上下文回憶下,BoolScript語(yǔ)言允許使用下面的代碼:(True & x) | y但是他未提供任何構(gòu)造讓你給變量x、y賦值。我應(yīng)該將語(yǔ)言設(shè)計(jì)成可以使用如下的代碼:x = Truey = False(True & x) | y但是我是故意忽略了賦值操作符=,使BoolScript代碼必須在包含定義了變量的值的上下文中執(zhí)行。這意味著當(dāng)Java程序用BoolScript腳本引擎計(jì)算一段文本代碼的值時(shí),同時(shí)需要將一個(gè)上下文提供給腳步引擎,或者至少要讓腳本引擎知道需要使用哪個(gè)上下文。你可以認(rèn)為上下文是Java程序和腳本引擎交換數(shù)據(jù)的袋子。JSR 223用接口javax.script.ScriptContext定義上下文這個(gè)結(jié)構(gòu)。如果我們向這個(gè)袋子里放入很多而又不加以組織的話,這個(gè)袋子就會(huì)變得非常凌亂。因此腳本上下文(例如ScriptContext的實(shí)例)將自己的數(shù)據(jù)劃分到了多個(gè)范圍里。JSR 223用接口javax.script.Bindings定義范圍這個(gè)結(jié)構(gòu)。圖三展示了上下文、上下文的范圍、以及范圍中存放的數(shù)據(jù)。 圖三 腳本引擎管理器和腳本引擎中的上下文和范圍。圖三里有些信息十分重要:1. 一個(gè)腳本引擎包含一個(gè)腳本上下文。2. 一個(gè)腳本引擎管理器(例如ScriptEngineManager的實(shí)例)都可以用來(lái)創(chuàng)建多個(gè)腳本引擎。3. 腳本引擎管理器包含一個(gè)被稱(chēng)為global scope的全局范圍,但是不包含上下文。4. 每個(gè)范圍基本上就是一個(gè)名稱(chēng)-值對(duì)的集合。圖三中可以看到有個(gè)一個(gè)范圍里包含兩個(gè)這樣的名稱(chēng)-值對(duì),一個(gè)的名稱(chēng)是x,另一個(gè)的名稱(chēng)是y。要注意每個(gè)范圍都是javas.script.Bindings的一個(gè)實(shí)例。5. 腳本引擎里的上下文包含了一個(gè)全局范圍、一個(gè)引擎范圍和0個(gè)或多個(gè)其他范圍。6. 一個(gè)腳本引擎可以用來(lái)執(zhí)行多個(gè)腳本(例如:腳本語(yǔ)言編寫(xiě)的多段單獨(dú)的腳本片斷)。但是圖三種的全局范圍和引擎范圍是什么呢?全局范圍是一個(gè)在多個(gè)腳本引擎中共享的范圍。如果你想在多個(gè)腳本引擎中共享一部分?jǐn)?shù)據(jù),那就可以將這些數(shù)據(jù)放在全局范圍中。注意全局范圍并不是對(duì)所有的腳本引擎來(lái)說(shuō)是全局的。它只對(duì)那些被它所在的腳本引擎管理器創(chuàng)建的腳步引起來(lái)說(shuō)是全局的。引擎范圍是一個(gè)被多個(gè)腳本貢享的范圍。如果你想要在多個(gè)腳本中共享數(shù)據(jù),那就可以將這些數(shù)據(jù)放在引擎范圍中。例如,假設(shè)我們有下面兩段腳本:(True & x) | y //Script A(True & x) //Script B如果我們要在這兩個(gè)腳本中共享x的值,我們可以把這個(gè)值放入執(zhí)行腳本的腳本引擎包含的引擎范圍中。假設(shè)現(xiàn)在我們只想在腳本A中保存y的值,那我們就需要?jiǎng)?chuàng)建一個(gè)范圍,記住這個(gè)范圍只對(duì)腳本A可見(jiàn),然后將y的值放入這個(gè)范圍中。作為例子,BoolScriptHostApp.java的main方法里用下面的代碼計(jì)算了(x & y)://bsEngine is an instance of ScriptEnginebsEngine.put('x', BoolTermEvaluator.tTrue);bsEngine.put('y', BoolTermEvaluator.tTrue);bsEngine.eval('x & ynn');這段代碼先將x和y的值放入引擎范圍內(nèi),然后調(diào)用引起的eval()方法執(zhí)行BoolScript代碼。如果你看下ScriptEngine接口,你會(huì)發(fā)現(xiàn)eval()方法有很多擁有不同參數(shù)的重載方法。如果像上面那樣使用字符串作為參數(shù)調(diào)用eval()方法,腳本引擎會(huì)在他的上下文中執(zhí)行這段代碼。如果不希望在腳本引擎的上下文中執(zhí)行,那就要在調(diào)用eval()時(shí)提供上下文。在我們的實(shí)現(xiàn)里,eval()的實(shí)際工作由BoolTermEvaluator里面的下面這段代碼執(zhí)行:public static BoolTerm evaluate(BoolTerm term, ScriptContext context){ ... else if (term instanceof Var) { Var var = (Var) term; Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE); if (!bindings.containsKey(var.getName())) throw new IllegalArgumentException('Variable ' + var.getName() + ' not set.'); Boolean varValue = (Boolean) bindings.get(var.getName()); if (varValue == Boolean.TRUE) return BoolTermEvaluator.tTrue; else return BoolTermEvaluator.tFalse; } ...}這個(gè)方法通過(guò)計(jì)算Term(True、 False、或變量)來(lái)執(zhí)行BoolScript代碼。當(dāng)Term像上面的代碼那樣是一個(gè)變量的時(shí)候,方法將調(diào)用作為參數(shù)傳入的上下文的getBindings()方法得到引擎范圍的引用。由于一個(gè)上下文里可以有多個(gè)范圍,所以我們使用ScriptContex.ENGINE_SCOPE表示我們想要得到的是引擎范圍。在得到引擎范圍后,我們使用變量名在引擎范圍中查找變量的值。如果未找到變量的值,則拋出異常。反之,我們將計(jì)算這個(gè)變量然后返回他的值。最后,我準(zhǔn)備解釋為什么腳本引擎管理器初始化腳本引擎的時(shí)候要調(diào)用腳本引擎的setBindings()方法:當(dāng)腳本引擎管理器調(diào)用引擎的setBindings()方法的時(shí)候,它將自己的全局范圍作為參數(shù)傳遞給這個(gè)方法。引擎則將這個(gè)全局范圍存入自己的上下文中。在結(jié)束這個(gè)章節(jié)前,讓我們看一下腳本API里的幾個(gè)類(lèi)。前面說(shuō)過(guò)ScriptEngineManager包含了一個(gè)Bindings的實(shí)例作為全局范圍。如果你看一下javax.script.ScriptEngineManager的源代碼,你可以發(fā)現(xiàn)有一個(gè)getBindings()方法用于得到ScriptEngineManager里的Bindings,同樣,還存在一個(gè)setBindings()用于設(shè)置ScriptEngineManager的Bindings。和ScriptEngineManager相似,ScriptEngine包含了一個(gè)ScriptContext的實(shí)例。在接口javax.script.ScriptEngine里也對(duì)應(yīng)存在一個(gè)getContext()方法和一個(gè)setBindings()方法。因此你可以很容易地在腳本引擎管理器之間共享全局范圍。你要做的僅僅是調(diào)用一個(gè)腳本引擎管理器的getBindings()方法得到它的全局范圍,然后調(diào)用另一個(gè)的setBindings()方法設(shè)置這個(gè)全局范圍。如果你看了示例里BoolScriptEngine的代碼,你會(huì)發(fā)現(xiàn)里面并沒(méi)有ScriptContext的引用。這是因?yàn)锽oolScriptEngine繼承了AbstractScriptEngine,而AbstractScriptEngine里有一個(gè)成員是ScriptContext的實(shí)例。如果你自己實(shí)現(xiàn)一個(gè)腳本引擎,而且沒(méi)有繼承父類(lèi)(如AbstractScriptEngine),那你就需要在你的腳本引擎里保存ScriptContext的實(shí)例,并且實(shí)現(xiàn)getContext()和setContext()方法。Compilable和Invocable到現(xiàn)在為止,我們已經(jīng)達(dá)到了把BoolScript做為JSR 223腳本引擎所需要的最低的要求。每當(dāng)Java程序需要使用我們的腳本引擎的時(shí)候,它需要將BoolScript代碼作為字符串傳遞給我們的引擎。引擎內(nèi)部使用一個(gè)解析器將這段字符串解析成抽象語(yǔ)法樹(shù)(abstract syntax tree),然后將棵樹(shù)交給BoolTermEvaluator.evaluate()執(zhí)行。以上的整個(gè)過(guò)程我們稱(chēng)為解釋執(zhí)行(interpretation),與之相對(duì)的是編譯執(zhí)行(compilation)。在這個(gè)過(guò)程中,BoolScript引擎被稱(chēng)為解釋器,與之相對(duì)的被稱(chēng)為編譯器。如果要作為編譯器使用的話,BoolScript引擎要能做到將文本的BoolScript代碼轉(zhuǎn)換成中間形態(tài),這樣在執(zhí)行這段代碼時(shí)就不用再解析成抽象語(yǔ)法樹(shù)。本章節(jié)講述了如何實(shí)現(xiàn)這個(gè)功能。Java程序是編譯成稱(chēng)為Java字節(jié)碼的中間形態(tài)存放在.class文件中。運(yùn)行時(shí)classloader載入.class文件,然后由JVM執(zhí)行字節(jié)碼。BoolScript將使用Java字節(jié)碼作為中間形態(tài),這樣就可以不用自己定義中間形態(tài)和實(shí)現(xiàn)自己的虛擬機(jī)。JSR 223定義的編譯概念的模型是javax.script.Compilable,因此BoolScriptEngine需要實(shí)現(xiàn)這個(gè)接口。下面這段BoolScriptHostApp.java里的代碼展示了如何使用可編譯的腳本引擎編譯和執(zhí)行腳本代碼:List boolAnswers = null;//bsEngine is an instance of ScriptEngineCompilable compiler = (Compilable) bsEngine;CompiledScript compiledScript = compiler.compile('x & ynn');Bindings bindings = new SimpleBindings();bindings.put('x', new Boolean(true));bindings.put('y', new Boolean(true));boolAnswers = (List) compiledScript.eval(bindings);printAnswers(boolAnswers);Invocable invocable = (Invocable) bsEngine;boolAnswers = (List) invocable.invoke('eval', new Boolean(true), new Boolean(false));printAnswers(boolAnswers);上面的代碼中,bsEngine是一個(gè)ScriptEngine的實(shí)例,它實(shí)現(xiàn)了Compilable接口。我們將它轉(zhuǎn)換成Compilable,然后調(diào)用compile()方法編譯代碼“x & y。compile()內(nèi)部將“x & y轉(zhuǎn)換成下面的Java代碼:package net.sf.model4lang.boolscript.generated;import java.util.*;import java.lang.reflect.*;class TempBoolClass { public static List eval(boolean x, boolean y) { List resultList = new ArrayList(); boolean result = false; result = x & y; resultList.add(new Boolean(result)); return resultList; }}這個(gè)轉(zhuǎn)換將BoolScript代碼轉(zhuǎn)換成Java類(lèi)中的一個(gè)方法。類(lèi)名和方法名都是硬編碼的。BoolScript里的每個(gè)變量都將成為Java方法的一個(gè)參數(shù)。將BoolScript代碼轉(zhuǎn)換成Java代碼只完成了一半的工作。之后我們還需要將Java代碼編譯成Java字節(jié)碼。在這我使用Java編譯API(JSR 199,Java SE 6.0的另一個(gè)新特性)直接在內(nèi)存中編譯Java代碼。本文不討論Java編譯API,感興趣的讀者可以參考資源部分查找更多的信息。Compilable接口規(guī)定了compile()方法必須返回一個(gè)CompiledScript的實(shí)例。CompiledScript在JSR 223里是用來(lái)定義編譯結(jié)果的模型。不論我們?cè)趺淳幾g腳本代碼,當(dāng)編譯結(jié)束的時(shí)候,我們必須將編譯的結(jié)果封裝成CompiledScript的實(shí)例。在示例代碼中,我們定義了一個(gè)類(lèi)BoolCompiledScript繼承CompiledScript,將編譯后的BoolScript代碼存放到這個(gè)類(lèi)中。當(dāng)腳本代碼編譯后,Java程序可以調(diào)用CompiledScript實(shí)例的eval()方法反復(fù)地執(zhí)行編譯后的代碼。在我們的例子中,我們調(diào)用CompiledScript的eval()方法的時(shí)候,需要將包含x和y變量的腳本上下文傳遞給這個(gè)方法,這在上面BoolScriptHostApp.java的代碼中已經(jīng)列出。CompiledScript的eval()并不是唯一可以執(zhí)行編譯后的腳本代碼的方法。如果腳本引擎實(shí)現(xiàn)了Invocable接口,我們就可以調(diào)用Invocable接口的invoke()方法執(zhí)行腳本代碼。在我們的簡(jiǎn)單示例中,調(diào)用這兩個(gè)方法執(zhí)行腳本代碼看上去并沒(méi)有什么區(qū)別。但是,實(shí)際使用中腳本引擎用戶通常用CompiledScript執(zhí)行整段腳本,而使用Invocable執(zhí)行獨(dú)立的函數(shù)(Java里稱(chēng)為方法)。如果你看一下Invocable的invoke()方法,你可以輕易地發(fā)現(xiàn)CompiledScript和Invocable的區(qū)別。和CompiledScript的eval()方法使用可選的腳本上下文作為參數(shù)不同的是,invoke()方法使用你想執(zhí)行的函數(shù)名作為參數(shù)。在上面引用的BoolScriptHostApp.java的代碼中,腳本引擎實(shí)例bsEngine實(shí)現(xiàn)了Invocable接口。我們將它轉(zhuǎn)成Invocable并調(diào)用它的invoke()方法。調(diào)用編譯后的腳本的函數(shù)和用反射調(diào)用Java類(lèi)的方法十分相似。你必須告訴invoke()方法你要調(diào)用的函數(shù)名,同時(shí)還要提供這個(gè)函數(shù)所需要的參數(shù)。我們已經(jīng)知道我們的函數(shù)名已經(jīng)硬編碼為eval了。因此我們將字符串“eval作為invoke的第一個(gè)參數(shù),同時(shí)我們還需要將eval的兩個(gè)Boolean參數(shù)傳遞給invoke()方法。結(jié)論在這篇文章里,我討論了JSR 223的幾個(gè)主要特性:腳本引擎發(fā)現(xiàn)機(jī)制、Java綁定、Compilable和Invocable。JSR 223中的Web腳本這里沒(méi)有涉及。如果了我們?cè)贐oolScript引擎里實(shí)現(xiàn)了Web腳本,那我們的腳本引擎使用者就可以在servlet容器里創(chuàng)建Web內(nèi)容了。即使不管和Java的整合,開(kāi)發(fā)一個(gè)語(yǔ)言的編譯器和解釋器也是一個(gè)龐大的事業(yè)。根據(jù)語(yǔ)言的復(fù)雜度,編譯器和解釋器的開(kāi)發(fā)可能會(huì)是一個(gè)非常麻煩的任務(wù)。感謝JSR 223,將我們的語(yǔ)言和Java整合從來(lái)沒(méi)有這么簡(jiǎn)單過(guò)。關(guān)于作者Chaur Wu 是一個(gè)軟件開(kāi)發(fā)人員并出版過(guò)書(shū)。他曾合著了有關(guān)設(shè)計(jì)模式和軟件建模的書(shū)籍。他同時(shí)也是開(kāi)源項(xiàng)目Model4Lang管理員,這個(gè)項(xiàng)目致力于為語(yǔ)言設(shè)計(jì)和構(gòu)造提供基于模型的解決方案。資源+本文中相關(guān)源代碼下載:http://www.javaworld.com/javaworld/jw-04-2006/scripting/jw-0424-scripting.zip+BSF網(wǎng)站:http://jakarta.apache.org/bsf/ +一個(gè)JSR 223腳本引擎:http://model4lang.sourceforge.net +JSR 223:http://www.jcp.org/en/jsr/detail?id=223 +Java SE 6.0源碼快照:http://download.java.net/jdk6 +Java SE 6.0 beta下載:http://java.sun.com/javase/6/download.jsp +JSR 199:http://www.jcp.org/en/jsr/detail?id=199 +Matrix:http://www.matrix.org.cn Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd 摘要即將發(fā)布的Java6.0包含了Java平臺(tái)腳本(JSR 223)的實(shí)現(xiàn)。這個(gè)JSR關(guān)注于程序設(shè)計(jì)語(yǔ)言以及他們與Java的整合。本文通過(guò)一個(gè)簡(jiǎn)單的“Boolean語(yǔ)言的實(shí)現(xiàn)展示了JSR 223的能力和潛力。通過(guò)這個(gè)例子,你將看到如何?
標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 郑州外墙清洗_郑州玻璃幕墙清洗_郑州开荒保洁-河南三恒清洗服务有限公司 | 澳门精准正版免费大全,2025新澳门全年免费,新澳天天开奖免费资料大全最新,新澳2025今晚开奖资料,新澳马今天最快最新图库-首页-东莞市傲马网络科技有限公司 | 衬塑设备,衬四氟设备,衬氟设备-淄博鲲鹏防腐设备有限公司 | 岛津二手液相色谱仪,岛津10A液相,安捷伦二手液相,安捷伦1100液相-杭州森尼欧科学仪器有限公司 | 乐泰胶水_loctite_乐泰胶_汉高乐泰授权(中国)总代理-鑫华良供应链 | 真空泵维修保养,普发,阿尔卡特,荏原,卡西亚玛,莱宝,爱德华干式螺杆真空泵维修-东莞比其尔真空机电设备有限公司 | 作文导航网_作文之家_满分作文_优秀作文_作文大全_作文素材_最新作文分享发布平台 | 强效碱性清洗剂-实验室中性清洗剂-食品级高纯氮气发生器-上海润榕科学器材有限公司 | 玖容气动液压设备有限公司-气液增压缸_压力机_增压机_铆接机_增压器 | 上海盐水喷雾试验机_两厢式冷热冲击试验箱-巨怡环试 | 济南货架定做_仓储货架生产厂_重型货架厂_仓库货架批发_济南启力仓储设备有限公司 | 楼承板-钢筋楼承板-闭口楼承板-无锡优贝斯楼承板厂 | EFM 022静电场测试仪-套帽式风量计-静电平板监测器-上海民仪电子有限公司 | 细沙回收机-尾矿干排脱水筛设备-泥石分离机-建筑垃圾分拣机厂家-青州冠诚重工机械有限公司 | 石油/泥浆/不锈钢防腐/砂泵/抽砂泵/砂砾泵/吸砂泵/压滤机泵 - 专业石油环保专用泵厂家 | 苏州同创电子有限公司 - 四探针测试仪源头厂家 | 医用空气消毒机-医用管路消毒机-工作服消毒柜-成都三康王 | 隔爆型防爆端子分线箱_防爆空气开关箱|依客思 | 自清洗过滤器_全自动过滤器_全自动反冲洗过滤器_量子过滤器-滑漮滴 | 小区健身器材_户外健身器材_室外健身器材_公园健身路径-沧州浩然体育器材有限公司 | 哈尔滨治「失眠/抑郁/焦虑症/精神心理」专科医院排行榜-京科脑康免费咨询 一对一诊疗 | 北京企业宣传片拍摄_公司宣传片制作-广告短视频制作_北京宣传片拍摄公司 | 蓝莓施肥机,智能施肥机,自动施肥机,水肥一体化项目,水肥一体机厂家,小型施肥机,圣大节水,滴灌施工方案,山东圣大节水科技有限公司官网17864474793 | 校园文化空间设计-数字化|中医文化空间设计-党建|法治廉政主题文化空间施工-山东锐尚文化传播公司 | 异噻唑啉酮-均三嗪-三丹油-1227-中北杀菌剂厂家 | 北京公积金代办/租房发票/租房备案-北京金鼎源公积金提取服务中心 | 混合气体腐蚀试验箱_盐雾/硫化氢/气体腐蚀试验箱厂家-北京中科博达 | 14米地磅厂家价价格,150吨地磅厂家价格-百科 | 大连海岛旅游网>>大连旅游,大连海岛游,旅游景点攻略,海岛旅游官网 | 激光内雕_led玻璃_发光玻璃_内雕玻璃_导光玻璃-石家庄明晨三维科技有限公司 激光内雕-内雕玻璃-发光玻璃 | 合肥汽车充电桩_安徽充电桩_电动交流充电桩厂家_安徽科帝新能源科技有限公司 | 广西绿桂涂料--承接隔热涂料、隔音涂料、真石漆、多彩仿石漆等涂料工程双包施工 | 郑州宣传片拍摄-TVC广告片拍摄-微电影短视频制作-河南优柿文化传媒有限公司 | 全自动面膜机_面膜折叠机价格_面膜灌装机定制_高速折棉机厂家-深圳市益豪科技有限公司 | 食品级焦亚硫酸钠_工业级焦亚硫酸钠_焦亚硫酸钠-潍坊邦华化工有限公司 | 隧道烘箱_隧道烘箱生产厂家-上海冠顶专业生产烘道设备 | 卡诺亚轻高定官网_卧室系统_整家定制_定制家居_高端定制_全屋定制加盟_定制家具加盟_定制衣柜加盟 | 老房子翻新装修,旧房墙面翻新,房屋防水补漏,厨房卫生间改造,室内装潢装修公司 - 一修房屋快修官网 | 东莞办公家具厂家直销-美鑫【免费3D效果图】全国办公桌/会议桌定制 | 快速卷帘门_硬质快速卷帘门-西朗门业 | 自动气象站_农业气象站_超声波气象站_防爆气象站-山东万象环境科技有限公司 |