久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

關(guān)于 Java Scripting API 您不知道的 5 件事

 lovespss 2010-10-23

 

簡介: Java? 語言足以滿足您的一些項(xiàng)目的需求,,但是腳本語言在性能方面一直表現(xiàn)不佳。Java Scripting API (javax.script) 支持在 Java 程序中調(diào)用腳本,,反之亦然,,通過本文,您將了解它在這兩方面是如何做到最好的,。


您認(rèn)為您已經(jīng)了解 Java 編程了嗎,?事實(shí)上,大多數(shù)開發(fā)人員只了解 Java 平臺的皮毛,,他們只學(xué)習(xí)了足以完成手頭工作所需要的知識而已,。在本 系列文章 中,Ted Neward 通過介紹 Java 平臺的核心功能來說明一些不為人所熟知的知識,,這些知識甚至可以幫助您解決最棘手的編程問題,。

現(xiàn)在,許多 Java 開發(fā)人員都喜歡在 Java 平臺中使用腳本語言,,但是使用編譯到 Java 字節(jié)碼中的動態(tài)語言有時(shí)是不可行的,。在某些情況中,直接編寫一個(gè) Java 應(yīng)用程序的腳本 部分 或者在一個(gè)腳本中調(diào)用特定的 Java 對象是更快捷,、更高效的方法,。

這就是 javax.script 產(chǎn)生的原因了。Java Scripting API 是從 Java 6 開始引入的,,它填補(bǔ)了便捷的小腳本語言和健壯的 Java 生態(tài)系統(tǒng)之間的鴻溝,。通過使用 Java Scripting API,您就可以在您的 Java 代碼中快速整合幾乎所有的腳本語言,這使您能夠在解決一些很小的問題時(shí)有更多可選擇的方法,。

1. 使用 jrunscript 執(zhí)行 JavaScript

每一個(gè)新的 Java 平臺發(fā)布都會帶來新的命令行工具集,,它們位于 JDK 的 bin 目錄。Java 6 也一樣,,其中 jrunscript 便是 Java 平臺工具集中的一個(gè)不小的補(bǔ)充,。

設(shè)想一個(gè)編寫命令行腳本進(jìn)行性能監(jiān)控的簡單問題。這個(gè)工具將借用 jmap(見本系列文章 前一篇文章 中的介紹),,每 5 秒鐘運(yùn)行一個(gè) Java 進(jìn)程,,從而了解進(jìn)程的運(yùn)行狀況。一般情況下,,我們會使用命令行 shell 腳本來完成這樣的工作,,但是這里的服務(wù)器應(yīng)用程序部署在一些差別很大的平臺上,包括 Windows? 和 Linux?,。系統(tǒng)管理員將會發(fā)現(xiàn)編寫能夠同時(shí)運(yùn)行在兩個(gè)平臺的 shell 腳本是很痛苦的,。通常的做法是編寫一個(gè) Windows 批處理文件和一個(gè) UNIX? shell 腳本,同時(shí)保證這兩個(gè)文件同步更新,。

但是,,任何閱讀過 The Pragmatic Programmer 的人都知道,這嚴(yán)重違反了 DRY (Don't Repeat Yourself) 原則,,而且會產(chǎn)生許多缺陷和問題,。我們真正希望的是編寫一種與操作系統(tǒng)無關(guān)的腳本,它能夠在所有的平臺上運(yùn)行,。

當(dāng)然,,Java 語言是平臺無關(guān)的,但是這里并不是需要使用 “系統(tǒng)” 語言的情況,。我們需要的是一種腳本語言 — 如,,JavaScript。

清單 1 顯示的是我們所需要的簡單 shell 腳本:


清單 1. periodic.js
            while (true)
            {
            echo("Hello, world!");
            }

由于經(jīng)常與 Web 瀏覽器打交道,,許多 Java 開發(fā)人員已經(jīng)知道了 JavaScript(或 ECMAScript,;JavaScript 是由 Netscape 開發(fā)的一種 ECMAScript 語言),。問題是,,系統(tǒng)管理員要如何運(yùn)行這個(gè)腳本?

當(dāng)然,,解決方法是 JDK 所帶的 jrunscript 實(shí)用程序,,如清單 2 所示:


清單 2. jrunscript
            C:\developerWorks\5things-scripting\code\jssrc>jrunscript periodic.js
            Hello, world!
            Hello, world!
            Hello, world!
            Hello, world!
            Hello, world!
            Hello, world!
            Hello, world!
            ...

注意,您也可以使用 for 循環(huán)按照指定的次數(shù)來循環(huán)執(zhí)行這個(gè)腳本,,然后才退出,。基本上,jrunscript 能夠讓您執(zhí)行 JavaScript 的所有操作,。惟一不同的是它的運(yùn)行環(huán)境不是瀏覽器,,所以運(yùn)行中不會有 DOM。因此,,最頂層的函數(shù)和對象稍微有些不同,。

因?yàn)?Java 6 將 Rhino ECMAScript 引擎作為 JDK 的一部分,jrunscript 可以執(zhí)行任何傳遞給它的 ECMAScript 代碼,,不管是一個(gè)文件(如此處所示)或是在更加交互式的 REPL(“Read-Evaluate-Print-Loop”)shell 環(huán)境,。運(yùn)行 jrunscript 就可以訪問 REPL shell。


2. 從腳本訪問 Java 對象

能夠編寫 JavaScript/ECMAScript 代碼是非常好的,,但是我們不希望被迫重新編譯我們在 Java 語言中使用的所有代碼 — 這是違背我們初衷的,。幸好,所有使用 Java Scripting API 引擎的代碼都完全能夠訪問整個(gè) Java 生態(tài)系統(tǒng),,因?yàn)楸举|(zhì)上一切代碼都還是 Java 字節(jié)碼,。所以,回到我們之前的問題,,我們可以在 Java 平臺上使用傳統(tǒng)的 Runtime.exec() 調(diào)用來啟動進(jìn)程,,如清單 3 所示:


清單 3. Runtime.exec() 啟動 jmap
            var p = java.lang.Runtime.getRuntime().exec("jmap", [ "-histo", arguments[0] ])
            p.waitFor()
            

數(shù)組 arguments 是指向傳遞到這個(gè)函數(shù)參數(shù)的 ECMAScript 標(biāo)準(zhǔn)內(nèi)置引用。在最頂層的腳本環(huán)境中,,則是傳遞給腳本本身的的參數(shù)數(shù)組(命令行參數(shù)),。所以,在清單 3 中,,這個(gè)腳本預(yù)期接收一個(gè)參數(shù),,該參數(shù)包含要映射的 Java 進(jìn)程的 VMID。

除此之外,,我們可以利用本身為一個(gè) Java 類的 jmap,,然后直接調(diào)用它的 main() 方法,如清單 4 所示,。有了這個(gè)方法,,我們不需要 “傳輸” Process 對象的 in/out/err 流。


清單 4. JMap.main()
            var args = [ "-histo", arguments[0] ]
            Packages.sun.tools.jmap.JMap.main(args)
            

Packages 語法是一個(gè) Rhino ECMAScript 標(biāo)識,,它指向已經(jīng) Rhino 內(nèi)創(chuàng)建的位于核心 java.* 包之外的 Java 包,。


3. 從 Java 代碼調(diào)用腳本

從腳本調(diào)用 Java 對象僅僅完成了一半的工作:Java 腳本環(huán)境也提供了從 Java 代碼調(diào)用腳本的功能。這只需要實(shí)例化一個(gè) ScriptEngine 對象,,然后加載和評估腳本,,如清單 5 所示:


清單 5. Java 平臺的腳本調(diào)用
            import java.io.*;
            import javax.script.*;
            public class App
            {
            public static void main(String[] args)
            {
            try
            {
            ScriptEngine engine =
            new ScriptEngineManager().getEngineByName("javascript");
            for (String arg : args)
            {
            FileReader fr = new FileReader(arg);
            engine.eval(fr);
            }
            }
            catch(IOException ioEx)
            {
            ioEx.printStackTrace();
            }
            catch(ScriptException scrEx)
            {
            scrEx.printStackTrace();
            }
            }
            }

eval() 方法也可以直接操作一個(gè) String,所以這個(gè)腳本不一定必須是文件系統(tǒng)的一個(gè)文件 — 它可以來自于數(shù)據(jù)庫,、用戶輸入,,或者甚至可以基于環(huán)境和用戶操作在應(yīng)用程序中生成。


4. 將 Java 對象綁定到腳本空間

僅僅調(diào)用一個(gè)腳本還不夠:腳本通常會與 Java 環(huán)境中創(chuàng)建的對象進(jìn)行交互。這時(shí),,Java 主機(jī)環(huán)境必須創(chuàng)建一些對象并將它們綁定,,這樣腳本就可以很容易找到和使用這些對象。這個(gè)過程是 ScriptContext 對象的任務(wù),,如清單 6 所示:


清單 6. 為腳本綁定對象
            import java.io.*;
            import javax.script.*;
            public class App
            {
            public static void main(String[] args)
            {
            try
            {
            ScriptEngine engine =
            new ScriptEngineManager().getEngineByName("javascript");
            for (String arg : args)
            {
            Bindings bindings = new SimpleBindings();
            bindings.put("author", new Person("Ted", "Neward", 39));
            bindings.put("title", "5 Things You Didn't Know");
            FileReader fr = new FileReader(arg);
            engine.eval(fr, bindings);
            }
            }
            catch(IOException ioEx)
            {
            ioEx.printStackTrace();
            }
            catch(ScriptException scrEx)
            {
            scrEx.printStackTrace();
            }
            }
            }

訪問所綁定的對象很簡單 — 所綁定對象的名稱是作為全局命名空間引入到腳本的,,所以在 Rhino 中使用 Person 很簡單,如清單 7 所示:


清單 7. 是誰撰寫了本文,?
            println("Hello from inside scripting!")
            println("author.firstName = " + author.firstName)
            

您可以看到,,JavaBeans 樣式的屬性被簡化為使用名稱直接訪問,這就好像它們是字段一樣,。


5. 編譯頻繁使用的腳本

腳本語言的缺點(diǎn)一直存在于性能方面,。其中的原因是,大多數(shù)情況下腳本語言是 “即時(shí)” 解譯的,,因而它在執(zhí)行時(shí)會損失一些解析和驗(yàn)證文本的時(shí)間和 CPU 周期,。運(yùn)行在 JVM 的許多腳本語言最終會將接收的代碼轉(zhuǎn)換為 Java 字節(jié)碼,至少在腳本被第一次解析和驗(yàn)證時(shí)進(jìn)行轉(zhuǎn)換,;在 Java 程序關(guān)閉時(shí),,這些即時(shí)編譯的代碼會消失。將頻繁使用的腳本保持為字節(jié)碼形式可以幫助提升可觀的性能,。

我們可以以一種很自然和有意義的方法使用 Java Scripting API,。如果返回的 ScriptEngine 實(shí)現(xiàn)了 Compilable 接口,那么這個(gè)接口所編譯的方法可用于將腳本(以一個(gè) String 或一個(gè) Reader 傳遞過來的)編譯為一個(gè) CompiledScript 實(shí)例,,然后它可用于在 eval() 方法中使用不同的綁定重復(fù)地處理編譯后的代碼,,如清單 8 所示:


清單 8. 編譯解譯后的代碼
            import java.io.*;
            import javax.script.*;
            public class App
            {
            public static void main(String[] args)
            {
            try
            {
            ScriptEngine engine =
            new ScriptEngineManager().getEngineByName("javascript");
            for (String arg : args)
            {
            Bindings bindings = new SimpleBindings();
            bindings.put("author", new Person("Ted", "Neward", 39));
            bindings.put("title", "5 Things You Didn't Know");
            FileReader fr = new FileReader(arg);
            if (engine instanceof Compilable)
            {
            System.out.println("Compiling....");
            Compilable compEngine = (Compilable)engine;
            CompiledScript cs = compEngine.compile(fr);
            cs.eval(bindings);
            }
            else
            engine.eval(fr, bindings);
            }
            }
            catch(IOException ioEx)
            {
            ioEx.printStackTrace();
            }
            catch(ScriptException scrEx)
            {
            scrEx.printStackTrace();
            }
            }
            }

在大多數(shù)情況中,CompiledScript 實(shí)例需要存儲在一個(gè)長時(shí)間存儲中(例如,,servlet-context),,這樣才能避免一次次地重復(fù)編譯相同的腳本。然而,,如果腳本發(fā)生變化,,您就需要創(chuàng)建一個(gè)新的 CompiledScript 來反映這個(gè)變化;一旦編譯完成,,CompiledScript 就不再執(zhí)行原始的腳本文件內(nèi)容,。


結(jié)束語

Java Scripting API 在擴(kuò)展 Java 程序的范圍和功能方面前進(jìn)了很大一步,并且它將腳本語言的編碼效率的優(yōu)勢帶到 Java 環(huán)境,。jrunscript — 它顯然不是很難編寫的程序 — 以及 javax.script 給 Java 開發(fā)人員帶來了諸如 Ruby (JRuby) 和 ECMAScript (Rhino) 等腳本語言的優(yōu)勢,,同時(shí)還不會破壞 Java 環(huán)境的生態(tài)系統(tǒng)和可擴(kuò)展性,。

請繼續(xù)閱讀下一篇文章 5 件事 系列文章:JDBC,。


參考資料

學(xué)習(xí)


    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多