精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

你不知道的Java秘密

開發 后端
本文向各位介紹一下Java性能監控小技巧:“JDK附帶分析器、遠程連接進程、跟蹤統計、為離線分析創建一個堆轉儲、JConsole并不是高深莫測的?!?/div>

51CTO給各位讀者講過《Java的8大技術優勢》,很多開發者覺得自己懂Java編程,事實是大多數開發人員都只領會到了Java平臺的皮毛,所學也只夠應付工作。作者將深度挖掘Java平臺的核心功能,揭示一些鮮為人知的事實,幫助您解決最棘手的編程困難。

當應用程序性能受到損害時,大多數開發人員都驚慌失措,這在情理之中。跟蹤Java應用程序瓶頸來源一直以來都是很麻煩的,因為Java虛擬機有黑盒效應,而且Java平臺分析工具一貫就有缺陷。

然而,隨著Java5中JConsole的引入,一切都發生了改變。JConsole是一個內置Java性能分析器,可以從命令行或在GUIshell中運行。它不是***的,但是當尖頭老板來問你關于性能的問題時,用它來應對還是綽綽有余的——這比查詢PapaGoogle要好得多。

我們將向您展示5個方法,使您可以輕松地使用JConsole(或者,它更高端的“近親”VisualVM)來監控Java應用程序性能和跟蹤Java中的代碼。

1.JDK附帶分析器

許多開發人員沒有意識到從Java 5開始JDK中包含了一個分析器。JConsole(或者Java平臺***版本,VisualVM)是一個內置分析器,它同Java編譯器一樣容易啟動。如果是從命令行啟動,使JDK在PATH上,運行jconsole即可。如果從GUIshell啟動,找到JDK安裝路徑,打開bin文件夾,雙擊jconsole。

當分析工具彈出時(取決于正在運行的Java版本以及正在運行的Java程序數量),可能會出現一個對話框,要求輸入一個進程的URL來連接,也可能列出許多不同的本地Java進程(有時包含JConsole進程本身)來連接。

使用JConsole進行工作

在Java 5中,Java進程并不是被設置為默認分析的,而是通過一個命令行參數—-Dcom.sun.management.jmxremote——在啟動時告訴Java 5 VM打開連接,以便分析器可以找到它們;當進程被JConsole撿起時,您只能雙擊它開始分析。

分析器有自己的開銷,因此***的辦法就是花點時間來弄清是什么開銷。發現JConsole開銷最簡單的辦法是,首先獨自運行一個應用程序,然后在分析器下運行,并測量差異。(應用程序不能太大或者太小;我最喜歡使用JDK附帶的SwingSet2樣本。)因此,我使用-verbose:gc嘗試運行SwingSet2來查看垃圾收集清理,然后運行同一個應用程序并將JConsole分析器連接到它。當JConsole連接好了之后,一個穩定的GC清理流出現,否則不會出現。這就是分析器的性能開銷。

JConsole或VisualVM?

JConsole從Java 5開始就隨著Java平臺版本一起發布,而VisualVM是在NetBeans基礎上升級的一個分析器,在Java 6的更新版12中***次發布。多數還沒有更新到Java 6,因此這篇文章主要介紹JConsole。然而,多數技巧和這兩個分析器都有關。

[[14591]]
51CTO推薦JVM專題

2.遠程連接進程

因為Web應用程序分析工具假設通過一個套接字進行連通性分析,您只需要進行少許配置來設置JConsole(或者是基于JVMTI的分析器,就這點而言),監控/分析遠程運行的應用程序。

如果Tomcat運行在一個名為“webserve”的機器上,且JVM已經啟動了JMX并監聽端口9004,從JConsole(或者任何JMX客戶端)連接它需要一個JMX URL“service:jmx:rmi:///jndi/rmi://webserver:9004/jmxrmi”。

基本上,要分析一個運行在遠程數據中心的應用程序服務器,您所需要的僅僅是一個JMX URL。

3.跟蹤統計

JConsole有許多對收集統計數據有用的選項卡,包括:

◆Memory:在JVM垃圾收集器中針對各個堆跟蹤活動。

◆Threads:在目標JVM中檢查當前線程活動。

◆Classes:觀察VM已加載類的總數。

這些選項卡(和相關的圖表)都是由每個Java 5及更高版本VM在JMX服務器上注冊的JMX對象提供的,是內置到JVM的。一個給定JVM中可用bean的完整清單在MBeans選項卡上列出,包括一些元數據和一個有限的用戶界面來查看數據或執行操作。(然而,注冊通知是在JConsole用戶界面之外。)

使用統計數據

假設一個Tomcat進程死于OutOfMemoryError。如果您想要弄清楚發生了什么,打開JConsole,單擊Classes選項卡,過一段時間查看一次類計數。如果數量穩定上升,您可以假設應用程序服務器或者您的代碼某個地方有一個ClassLoader漏洞,不久之后將耗盡PermGen空間。如果需要更進一步的確認問題,請看Memory選項卡。

不要成為典型

發現應用程序代碼中性能問題的常用響應多種多樣,但也是可預測的。早期的Java編程人員對舊的IDE可能十分生氣,并開始進行代碼庫中主要部分的代碼復查,在源代碼中尋找熟悉的“紅色標志”,像異步塊、對象配額等等。隨著編程經驗的增加,開發人員可能會仔細研究JVM支持的-X標志,尋找優化垃圾收集器的方法。當然,對于新手,直接去Google查詢,希望有其他人發現了JVM的神奇的“make it go fast”轉換,避免重寫代碼。

從本質上來說,這些方法沒什么錯,但都是有風險的。對于一個性能問題最有效的響應就是使用一個分析器——現在它們內置在Java平臺,我們確實沒有理由不這樣做!

4.為離線分析創建一個堆轉儲

生產環境中一切都在快速地進行著,您可能沒有時間花費在您的應用程序分析器上,相反地,您可以為Java環境中的每個事件照一個快照保存下來過后再看。在JConsole中您也可以這樣做,在VisualVM中甚至會做得更好。
先找到MBeans選項卡,在其中打開com.sun.management節點,接著是HotSpotDiagnostic節點。現在,選擇Operations,注意右邊面板中的“dumpHeap”按鈕。如果您在***個(“字符串”)輸入框中向dumpHeap傳遞一個文件名來轉儲,它將為整個JVM堆照一個快照,并將其轉儲到那個文件。

稍后,您可以使用各種不同的商業分析器來分析文件,或者使用VisualVM分析快照。(記住,VisualVM是在Java 6中可用的,且是單獨下載的。)

5.JConsole并不是高深莫測的

作為一個分析器實用工具,JConsole是極好的,但是還有更好的工具。一些分析插件附帶分析器或者靈巧的用戶界面,默認情況下比JConsole跟蹤更多的數據。

JConsole真正吸引人的是整個程序是用“普通舊式Java”編寫的,這意味著任何Java開發人員都可以編寫這樣一個實用工具。事實上,JDK其中甚至包括如何通過創建一個插件來定制JConsole的示例。建立在NetBeans頂部的VisualVM進一步延伸了插件概念。

如果JConsole(或者VisualVM,或者其他任何工具)不符合您的需求,或者不能跟蹤您想要跟蹤的,或者不能按照您的方式跟蹤,您可以編寫屬于自己的工具。如果您覺得Java代碼很麻煩,Groovy或JRuby或很多其他JVM語言都可以幫助您更快完成。

您真正需要的是一個快速而粗糙(quick-and-dirty)的由JVM連接的命令行工具,可以以您想要的方式確切地跟蹤您感興趣的數據。

#p#

5個命令行分析工具

全功能內置分析器,如JConsole和VisualVM的成本有時比它們的性能費用還要高—尤其是在生產軟件上運行的系統中。因此,在聚焦Java性能監控的第2篇中,我將介紹5個命令行分析工具,使開發人員僅關注運行的Java進程的一個方面。

JDK包括很多命令行實用程序,可以用于監控和管理Java應用程序性能。雖然大多數這類應用程序都被標注為“實驗型”,在技術上不受支持,但是它們很有用。

1.jps(sun.tools.jps)

很多命令行工具都要求您識別您希望監控的Java進程。這與監控本地操作系統進程、同樣需要一個程序識別器的同類工具沒有太大區別。

“VMID”識別器與本地操作系統進程識別器(“pid”)并不總是相同的,這就是我們需要JDKjps實用程序的原因。

在Java進程中使用jps

與配置JDK的大部分工具及本文中提及的所有工具一樣,可執行jps通常是一個圍繞Java類或執行大多數工作的類集的一個薄包裝。在Windows®環境下,這些工具是.exe文件,使用JNIInvocationAPI直接調用上面提及的類;在UNIX®環境下,大多數工具是一個shell腳本的符號鏈接,該腳本采用指定的正確類名稱開始一個普通啟動程序。如果您希望在Java進程中使用jps(或者任何其他工具)的功能—Ant腳本—僅在每個工具的“主”類上調用main()相對容易。為了簡化引用,類名稱出現在每個工具名稱之后的括號內。

jps—名稱反映了在大多數UNIX系統上發現的ps實用程序—告訴我們運行Java應用程序的JVMID。顧名思義,jps返回指定機器上運行的所有已發現的Java進程的VMID。如果jps沒有發現進程,并不意味著無法附加或研究Java進程,而只是意味著它并未宣傳自己的可用性。

如果發現Java進程,jps將列出啟用它的命令行。這種區分Java進程的方法非常重要,因為只要涉及操作系統,所有的Java進程都被統稱為“java”。在大多數情況下,VMID是值得注意的重要數字。

使用分析器開始

使用分析實用程序開始的最簡單方法是使用一個如在demo/jfc/SwingSet2中發現的SwingSet2演示一樣的演示程序。這樣就可以避免程序作為背景/監控程序運行時出現掛起的可能性。當您了解工具及其費用后,就可以在實際程序中進行試用。

加載演示應用程序后,運行jps并注意返回的vmid。為了獲得更好的效果,采用-Dcom.sun.management.jmxremote屬性集啟動Java進程。如果沒有使用該設置,部分下列工具收集的部分數據可能不可用。

2.jstat(sun.tools.jstat)

jstat實用程序可以用于收集各種各樣不同的統計數據。jstat統計數據被分類到“選項”中,這些選項在命令行中被指定作為***參數。對于JDK 1.6來說,您可以通過采用命令-options運行jstat查看可用的選項清單。清單1中顯示了部分選項:

清單1.jstat選項

  1.  
  2.  
  3. -class  
  4. -compiler  
  5. -gc  
  6. -gccapacity  
  7. -gccause  
  8. -gcnew  
  9. -gcnewcapacity  
  10. -gcold  
  11. -gcoldcapacity  
  12. -gcpermcapacity  
  13. -gcutil  
  14. -printcompilation   

實用程序的JDK記錄將告訴您清單1中每個選項返回的內容,但是其中大多數用于收集垃圾的收集器或者其部件的性能信息。-class選項顯示了加載及未加載的類(使其成為檢測應用程序服務器或代碼中ClassLoader泄露的重要實用程序,且-compiler和-printcompilation都顯示了有關Hotspot JIT編譯程序的信息。

默認情況下,jstat在您核對信息時顯示信息。如果您希望每隔一定時間拍攝快照,請在-options指令后以毫秒為單位指定間隔時間。jstat將持續顯示監控進程信息的快照。如果您希望jstat在終止前進行特定數量的快照,在間隔時間/時間值后指定該數字。

如果5756是幾分鐘前開始的運行SwingSet2程序的VMID,那么下列命令將告訴jstat每250毫秒為10個佚代執行一次gc快照轉儲,然后停止:

  1. jstat -gc 5756 250 10 

請注意Sun(現在的Oracle)保留了在不進行任何預先通知的情況下更改各種選項的輸出甚至是選項本身的權利。這是使用不受支持實用程序的缺點。請參看Javadocs了解jstat輸出中每一列的全部細節。

3.jstack(sun.tools.jstack)

了解Java進程及其對應的執行線程內部發生的情況是一種常見的診斷挑戰。例如,當一個應用程序突然停止進程時,很明顯出現了資源耗盡,但是僅通過查看代碼無法明確知道何處出現資源耗盡,且為什么會發生。

jstack是一個可以返回在應用程序上運行的各種各樣線程的一個完整轉儲的實用程序,您可以使用它查明問題。

采用期望進程的VMID運行jstack會產生一個堆轉儲。就這一點而言,jstack與在控制臺窗口內按Ctrl-Break鍵起同樣的作用,在控制臺窗口中,Java進程正在運行或調用VM內每個Thread對象上的Thread.getAllStackTraces()或Thread.dumpStack()。jstack調用也轉儲關于在VM內運行的非Java線程的信息,這些線程作為Thread對象并不總是可用的。

jstack的-l參數提供了一個較長的轉儲,包括關于每個Java線程持有鎖的更多詳細信息,因此發現(和squash)死鎖或可伸縮性bug是極其重要的。

4.jmap(sun.tools.jmap)

有時,您正在處理的問題是一個對象泄露,如一個ArrayList(可能持有成千上萬個對象)該釋放時沒有釋放。另一個更普遍的問題是,看似從不會壓縮的擴展堆,卻有活躍的垃圾收集。

當您努力尋找一個對象泄露時,在指定時刻對堆及時進行拍照,然后審查其中內容非常有用。jmap通過對堆拍攝快照來提供該功能的***部分。然后您可以采用下一部分中描述的jhat實用程序分析堆數據。

與這里描述的其他所有實用程序一樣,使用jmap非常簡單。將jmap指向您希望拍快照的Java進程的VMID,然后給予它部分參數,用來描述產生的結果文件。您要傳遞給jmap的選項包括轉儲文件的名稱以及是否使用一個文本文件或二進制文件。二進制文件是最有用的選項,但是只有當與某一種索引工具結合使用時—通過十六進制值的文本手動操作數百兆字節不是***的方法。

隨意看一下Java堆的更多信息,jmap同樣支持-histo選項。-histo產生一個對象文本柱狀圖,現在在堆中大量引用,由特定類型消耗的字節總數分類。它同樣給出了特定類型的總示例數量,支持部分原始計算,并猜測每個實例的相對成本。

不幸的是,jmap沒有像jstat一樣的period-and-max-count選項,但是將jmap(或jmap.main())調用放入shell腳本或其他類的循環,周期性地拍攝快照相對簡單。(事實上,這是加入jmap的一個好的擴展,不管是作為OpenJDK本身的源補丁,還是作為其他實用程序的擴展。)

5.jhat(com.sun.tools.hat.Main)

將堆轉儲至一個二進制文件后,您就可以使用jhat分析二進制堆轉儲文件。jhat創建一個HTTP/HTML服務器,該服務器可以在瀏覽器中被瀏覽,提供一個關于堆的object-by-object視圖,及時凍結。根據對象引用草率處理堆可能會非??尚Γ梢酝ㄟ^對總體混亂進行某種自動分析而獲得更好的服務。幸運的是,jhat支持OQL語法進行這樣的分析。

例如,對所有含有超過100個字符的String運行OQL查詢看起來如下:

  1. select s from java.lang.String s where s.count >= 100 

結果作為對象鏈接顯示,然后展示該對象的完整內容,字段引用作為可以解除引用的其他鏈接的其他對象。OQL查詢同樣可以調用對象的方法,將正則表達式作為查詢的一部分,并使用內置查詢工具。一種查詢工具,referrers()函數,顯示了引用指定類型對象的所有引用。下面是尋找所有參考File對象的查詢:

  1. select referrers(f) from java.io.File f  

您可以查找OQL的完整語法及其在jhat瀏覽器環境內“OQL Help”頁面上的特性。將jhat與OQL相結合是對行為不當的堆進行對象調查的有效方法。

結束語

當您需要近距離觀察Java進程內發生的事情時,JDK的分析擴展會非常有用。本文中介紹的所有工具都可以從命令行中由其自己使用。它們還可以與JConsole或VisualVM有力地結合使用。JConsole和VisualVM提供Java虛擬機的總體視圖,jstat和jmap等有針對性的工具支持您對研究進行微調。

#p#

Java 平臺上更簡單的腳本編寫方法

現在,許多 Java 開發人員都喜歡在 Java 平臺中使用腳本語言,但是使用編譯到 Java 字節碼中的動態語言有時是不可行的。在某些情況中,直接編寫一個 Java 應用程序的腳本 部分 或者在一個腳本中調用特定的 Java 對象是更快捷、更高效的方法。

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

1. 使用 jrunscript 執行 JavaScript

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

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

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

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

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

清單 1. periodic.js

  1.  
  2.  
  3. while (true)  
  4. {  
  5.     echo("Hello, world!");  
  6. }  

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

當然,解決方法是 JDK 所帶的 jrunscript 實用程序,如清單 2 所示:

清單 2. jrunscript

  1.  
  2.       
  3. C:\developerWorks\5things-scripting\code\jssrc>jrunscript periodic.js  
  4. Hello, world!  
  5. Hello, world!  
  6. Hello, world!  
  7. Hello, world!  
  8. Hello, world!  
  9. Hello, world!  
  10. Hello, world!  
  11. ... 

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

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

2. 從腳本訪問 Java 對象

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

清單 3. Runtime.exec() 啟動 jmap

  1.  
  2.  
  3. var p = java.lang.Runtime.getRuntime().exec("jmap", [ "-histo", arguments[0] ])  
  4. p.waitFor()  

數組 arguments 是指向傳遞到這個函數參數的 ECMAScript 標準內置引用。在最頂層的腳本環境中,則是傳遞給腳本本身的的參數數組(命令行參數)。所以,在清單 3 中,這個腳本預期接收一個參數,該參數包含要映射的 Java 進程的 VMID。

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

清單 4. JMap.main()

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

Packages 語法是一個 Rhino ECMAScript 標識,它指向已經 Rhino 內創建的位于核心 java.* 包之外的 Java 包。

3. 從 Java 代碼調用腳本

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

清單 5. Java 平臺的腳本調用

  1. import java.io.*;  
  2. import javax.script.*;  
  3.  
  4. public class App  
  5. {  
  6.     public static void main(String[] args)  
  7.     {  
  8.         try  
  9.         {  
  10.             ScriptEngine engine =   
  11.                 new ScriptEngineManager().getEngineByName("javascript");  
  12.             for (String arg : args)  
  13.             {  
  14.                 FileReader fr = new FileReader(arg);  
  15.                 engine.eval(fr);  
  16.             }  
  17.         }  
  18.         catch(IOException ioEx)  
  19.         {  
  20.             ioEx.printStackTrace();  
  21.         }  
  22.         catch(ScriptException scrEx)  
  23.         {  
  24.             scrEx.printStackTrace();  
  25.         }  
  26.     }  
  27. }  

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

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

僅僅調用一個腳本還不夠:腳本通常會與 Java 環境中創建的對象進行交互。這時,Java 主機環境必須創建一些對象并將它們綁定,這樣腳本就可以很容易找到和使用這些對象。這個過程是 ScriptContext 對象的任務,如清單 6 所示:

清單 6. 為腳本綁定對象

  1.  
  2.       
  3. import java.io.*;  
  4. import javax.script.*;  
  5.  
  6. public class App  
  7. {  
  8.     public static void main(String[] args)  
  9.     {  
  10.         try  
  11.         {  
  12.             ScriptEngine engine =   
  13.                 new ScriptEngineManager().getEngineByName("javascript");  
  14.                   
  15.             for (String arg : args)  
  16.             {  
  17.                 Bindings bindings = new SimpleBindings();  
  18.                 bindings.put("author", new Person("Ted", "Neward", 39));  
  19.                 bindings.put("title", "5 Things You Didn't Know");  
  20.                   
  21.                 FileReader fr = new FileReader(arg);  
  22.                 engine.eval(fr, bindings);  
  23.             }  
  24.         }  
  25.         catch(IOException ioEx)  
  26.         {  
  27.             ioEx.printStackTrace();  
  28.         }  
  29.         catch(ScriptException scrEx)  
  30.         {  
  31.             scrEx.printStackTrace();  
  32.         }  
  33.     }  
  34. }  

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

清單 7. 

  1.  
  2.       
  3. println("Hello from inside scripting!")  
  4.  
  5. println("author.firstName = " + author.firstName)  

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

5. 編譯頻繁使用的腳本

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

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

清單 8. 編譯解譯后的代碼

  1.       
  2. import java.io.*;  
  3. import javax.script.*;  
  4.  
  5. public class App  
  6. {  
  7.     public static void main(String[] args)  
  8.     {  
  9.         try  
  10.         {  
  11.             ScriptEngine engine =   
  12.                 new ScriptEngineManager().getEngineByName("javascript");  
  13.                   
  14.             for (String arg : args)  
  15.             {  
  16.                 Bindings bindings = new SimpleBindings();  
  17.                 bindings.put("author", new Person("Ted", "Neward", 39));  
  18.                 bindings.put("title", "5 Things You Didn't Know");  
  19.                   
  20.                 FileReader fr = new FileReader(arg);  
  21.                 if (engine instanceof Compilable)  
  22.                 {  
  23.                     System.out.println("Compiling....");  
  24.                     Compilable compEngine = (Compilable)engine;  
  25.                     CompiledScript cs = compEngine.compile(fr);  
  26.                     cs.eval(bindings);  
  27.                 }  
  28.                 else  
  29.                     engine.eval(fr, bindings);  
  30.             }  
  31.         }  
  32.         catch(IOException ioEx)  
  33.         {  
  34.             ioEx.printStackTrace();  
  35.         }  
  36.         catch(ScriptException scrEx)  
  37.         {  
  38.             scrEx.printStackTrace();  
  39.         }  
  40.     }  
  41. }  

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

結束語

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

關于作者

[[14592]]
Ted Neward

Ted Neward是Neward&Associates的總裁,從事關于Java、.NET、XML Services以及其他平臺方面的咨詢、指導和演示等工作。他居住在華盛頓西雅圖。

【編輯推薦】

  1. 淺談Java最終勝出的8大技術優勢
  2. 編程思想碰撞 Scala不是改良的Java
  3. Flex與Java編程語言的相似之處 
  4. Java搜索引擎技術分解(一): 網絡爬蟲
  5. 衰亡? 15歲的Java才到青春期
責任編輯:佚名 來源: developerWorks
相關推薦

2011-07-11 15:52:47

RCWindows

2011-05-29 17:04:10

筆記本體驗

2025-07-23 07:40:29

2020-06-12 09:20:33

前端Blob字符串

2020-07-28 08:26:34

WebSocket瀏覽器

2018-02-07 08:21:42

2020-09-01 08:01:01

生成樹協議STP網絡協議

2022-03-10 09:11:33

JavaScrip開發JSON

2009-12-10 09:37:43

2022-10-13 11:48:37

Web共享機制操作系統

2021-02-01 23:23:39

FiddlerCharlesWeb

2011-09-15 17:10:41

2015-06-11 16:48:46

2011-05-04 14:55:22

耗材打印機

2016-12-15 17:15:44

2022-11-04 08:19:18

gRPC框架項目

2020-09-15 08:35:57

TypeScript JavaScript類型

2021-10-17 13:10:56

函數TypeScript泛型

2021-12-29 11:38:59

JS前端沙箱

2021-12-22 09:08:39

JSON.stringJavaScript字符串
點贊
收藏

51CTO技術棧公眾號

国产又粗又黄又猛| 久久国产精品免费观看| 无码人妻精品一区二区50| 亚洲人成网亚洲欧洲无码| 亚洲日本在线观看| 波多野结衣久草一区| 日本熟伦人妇xxxx| 亚洲精品456| 91传媒视频在线播放| 一区二区三区国产福利| av官网在线观看| 日韩午夜电影| 日日骚久久av| 特黄aaaaaaaaa真人毛片| 99精品在免费线中文字幕网站一区| 亚洲欧美偷拍另类a∨色屁股| av色综合网| 人妻 日韩精品 中文字幕| 色无极亚洲影院| 欧美视频一区在线观看| 伊人再见免费在线观看高清版| 色欲久久久天天天综合网| 日韩电影在线免费| 欧美老肥婆性猛交视频| 免费看污片网站| 日韩中文字幕| 欧美日韩三级在线| 99色这里只有精品| 免费网站成人| av观看在线| 亚洲高清影院| 激情久久av一区av二区av三区| 国产精品国产一区二区| 亚洲熟女乱色一区二区三区久久久| 国语自产精品视频在线看8查询8| 这里只有视频精品| 三级男人添奶爽爽爽视频 | 久久99久久99精品中文字幕| 黄瓜视频污在线观看| 日韩免费高清视频网站| 欧美色成人综合| 超碰97人人射妻| 久草免费在线色站| 亚洲三级免费观看| 亚洲成色最大综合在线| 欧美日韩国产综合视频| 成人做爰69片免费看网站| 成人福利网站在线观看| 台湾佬中文在线| 国产综合自拍| 久久久91精品| 日本激情视频一区二区三区| 国产一区二区三区四区二区 | 97精品伊人久久久大香线蕉| 欧美三级黄色大片| 久久精品不卡| 国产性色av一区二区| 97人妻精品一区二区三区免| 99这里只有精品视频| 欧美一级日韩一级| 污污的视频免费观看| 欧美野外wwwxxx| 国产精品麻豆视频| 欧美日韩亚洲一区二区三区在线观看 | 国产精品入口夜色视频大尺度 | 欧美日韩在线看| 激情伊人五月天| 高清精品在线| 五月激情综合色| 国产特级淫片高清视频| 激情aⅴ欧美一区二区欲海潮| 亚洲一区影音先锋| 国产玉足脚交久久欧美| www视频在线观看| 亚洲卡通动漫在线| 中文字幕中文字幕99| 人人干在线视频| 亚洲欧美激情插| 中文精品无码中文字幕无码专区| www视频在线免费观看| 亚洲精品成人a在线观看| 黄色影视在线观看| 四虎影视成人| 偷拍日韩校园综合在线| 日本免费一级视频| 成人在线中文| 在线91免费看| 国产一线在线观看| 亚洲成在人线免费观看| 一区二区三区视频免费| 91大神福利视频| 中文字幕亚洲精品乱码| 午夜精品久久久久久久男人的天堂| 99精品视频99| 日本在线不卡视频| 亚洲在线一区二区| 无码国产色欲xxxx视频| 国产欧美日韩综合精品一区二区| 久久综合福利| 欧美日韩在线精品一区二区三区激情综 | 91久久精品国产91久久| 丰满人妻一区二区三区无码av | 我不卡一区二区| 91成人影院| **欧美日韩vr在线| 亚洲中文一区二区三区| 狠狠色丁香久久婷婷综合丁香| 91在线无精精品一区二区| 你懂的网站在线| 国产视频一区在线播放| 亚洲精品天堂成人片av在线播放| 玛丽玛丽电影原版免费观看1977 | 久久亚洲AV成人无码国产野外| 欧美色图国产精品| 欧美激情国产高清| 无码人妻av免费一区二区三区| 精品亚洲国产成人av制服丝袜| 国产精品二区二区三区| 高清中文字幕一区二区三区| 亚洲一区二区三区在线看| 可以免费观看av毛片| 综合伊人久久| 国产一区二区久久精品| 欧美片一区二区| 免费成人性网站| 久久久精彩视频| 日本三级在线播放完整版| 一个色综合av| 亚洲一级免费观看| 久久久久久久久久久久久久久久久久久久 | 中文字幕欧美日本乱码一线二线| japanese在线播放| 成人做爰视频www网站小优视频| 欧美一级日韩不卡播放免费| 欧美丰满少妇人妻精品| 好吊日精品视频| 成人国产精品一区| 四虎精品在线| 亚洲国产精品久久久久婷婷884| 在线观看岛国av| 久久99国产精一区二区三区| 久久久噜噜噜久噜久久| 国产伦精品一区二区三区免.费| 91在线云播放| 伊人再见免费在线观看高清版| 国产成人午夜性a一级毛片| 精品国产精品网麻豆系列| 中文字幕在线观看2018| 秋霞国产午夜精品免费视频| 国产一区二区免费电影| 狂野欧美激情性xxxx欧美| 91麻豆精品国产91久久久资源速度 | 日本在线播放不卡| 国偷自产一区二区免费视频| 亚洲精品久久在线| 91看片在线播放| 99久久婷婷国产| 欧美亚洲精品一区二区| 成人性生交大片免费看96| 久久91精品国产| 不卡av中文字幕| 亚洲自拍偷拍欧美| 在线播放av中文字幕| 五月激情综合| 91在线中文字幕| av免费在线免费| 欧美一区二区三区视频| 国产黄在线免费观看| 黑人巨大精品欧美一区| 国产免费色视频| 欧美日韩在线精品一区二区三区激情综合 | 69精品丰满人妻无码视频a片| 日韩精品一区二区三区中文在线| 一本色道久久综合亚洲精品小说| 最近中文字幕免费在线观看| 中文字幕在线不卡| www.久久com| 黄色欧美日韩| 你懂的视频在线一区二区| 香蕉成人av| 精品久久久999| 精品国产乱码一区二区三 | 久久久久香蕉视频| 丁香天五香天堂综合| 国产亚洲黄色片| 免费观看成人www动漫视频| 777午夜精品福利在线观看| 五月天婷婷激情网| 色婷婷激情综合| 国产又粗又黄又猛| 国产一区二区在线视频| 美女黄色免费看| 久久综合色占| 91色琪琪电影亚洲精品久久| av色在线观看| 亚洲欧洲午夜一线一品| 一级特黄aaa大片| 亚洲精品视频免费观看| 一区二区三区四区影院| 亚洲AV无码成人精品区明星换面 | 久久中文免费视频| av电影在线观看不卡| 成年人在线观看视频免费| 欧美高清视频在线观看mv| 国产日韩欧美在线看| 成人影音在线| 国产一区二区av| 亚洲精品国产av| 在线欧美日韩国产| 久久久久久久久久久久久久免费看| 91丨porny丨最新| 精品综合久久久久| 一本色道久久综合亚洲精品高清| 亚洲精品中文字幕乱码三区不卡| 综合激情网...| 成人免费xxxxx在线观看| 亚洲天堂免费电影| 欧美福利视频在线| 思思99re6国产在线播放| 亚洲黄一区二区| 国产男男gay体育生白袜| 欧美午夜精品久久久久久浪潮| 男人晚上看的视频| 久久色.com| 99久久免费看精品国产一区| 九九久久精品视频| 精品视频无码一区二区三区| 亚洲无毛电影| 一区二区不卡在线视频 午夜欧美不卡' | 国产精品无码AV| 欧美性猛xxx| 天堂资源在线播放| 亚洲精品久久嫩草网站秘色| 波多野结衣av在线观看| 白白色 亚洲乱淫| 在线视频日韩欧美| 麻豆成人在线观看| 日韩欧美黄色大片| 亚洲深夜激情| 男插女免费视频| 全球成人免费直播| 日本午夜精品一区二区三区| 超碰97久久国产精品牛牛| 91系列在线播放| 全球最大av网站久久| 欧美重口另类videos人妖| 欧美1234区| 欧美风情在线观看| 国产黄色小视频在线| 一区二区在线免费视频| 噜噜噜噜噜在线视频| 日韩电影中文字幕av| 欧美熟妇乱码在线一区| 精品国产髙清在线看国产毛片| 国产精品国产三级国产普通话对白| 在线观看日韩国产| 亚洲 欧美 日韩 在线| 欧美午夜视频在线观看| 在线观看国产亚洲| 精品福利视频导航| 五月天激情国产综合婷婷婷| 同产精品九九九| 国内自拍视频在线播放| 岛国精品视频在线播放| 成年免费在线观看| 精品日韩中文字幕| 国产精品一区二区三区四| 日韩欧美国产免费播放| youjizz在线视频| 欧美视频一区二区三区四区 | 视频一区欧美| 午夜精品短视频| 欧美日韩在线网站| 亚洲欧洲久久| 99久久久久久中文字幕一区| 懂色av一区二区三区四区五区| 欧美伊人久久| 青青草国产免费| 亚洲免费在线| 国产三级国产精品国产专区50| 久久er精品视频| 波多野结衣中文字幕在线播放| 国产成人av自拍| 亚洲精品中文字幕在线播放| www精品美女久久久tv| 欧美a在线播放| 亚洲猫色日本管| 1级黄色大片儿| 欧美中文字幕一区二区三区亚洲| 国产裸体永久免费无遮挡| 日韩精品一区二区在线| 日产精品久久久久久久性色| 国产一区二区三区欧美| 黄色成人在线| 性色av一区二区三区免费| 春暖花开亚洲一区二区三区| 91久久久久久久| 牲欧美videos精品| 韩国黄色一级大片| 99精品视频免费| 亚洲欧美日韩一二三区| 久久精品免视看| 久久精品美女视频| 欧美精三区欧美精三区| 日本亚洲一区| 欧美激情亚洲自拍| 97久久精品一区二区三区的观看方式 | 欧美激情精品久久久久久小说| 国内精品自线一区二区三区视频| 喷水视频在线观看| 亚洲美女少妇撒尿| 亚洲成人av网址| 日韩国产欧美精品在线| 最爽无遮挡行房视频在线| 国产精品999999| 色综合久久中文| 国产a级片网站| 国产激情91久久精品导航| jizz日本在线播放| 色综合久久久久久久久| 深爱激情五月婷婷| 久久6精品影院| 国产情侣一区在线| 亚洲一区二区免费视频软件合集| 久久国产欧美| 亚洲av无码成人精品国产| 亚洲成人777| 黄色小视频免费观看| 久久国产精品免费视频| 亚洲一区导航| 亚洲精品成人自拍| 日韩不卡一区二区三区| 三级网站在线免费观看| 欧美日韩免费观看中文| 污视频在线免费观看| 欧美丰满少妇xxxxx做受| 亚洲欧洲国产精品一区| 91亚洲精品国产| 不卡视频一二三四| 99re8这里只有精品| 中日韩av在线播放| 久久―日本道色综合久久| 国产在线欧美在线| 日韩精品一区二区在线| 欧美xxxx性xxxxx高清| 91精品黄色| 欧美日韩国产亚洲一区| 亚洲成人福利视频| 亚洲成人免费视| 蜜桃91麻豆精品一二三区| 久久久亚洲国产| 日韩精品丝袜美腿| 成人观看免费完整观看| 国产无人区一区二区三区| 老熟妇一区二区三区啪啪| 日韩在线小视频| 日韩精品一区二区三区中文字幕 | 亚洲欧美日韩视频二区| 亚洲第九十七页| 日本丰满少妇一区二区三区| 国产二区视频在线观看| 国产日韩中文字幕在线| 午夜天堂精品久久久久| 三级视频网站在线观看| 欧美性猛xxx| 色大18成网站www在线观看| 亚洲一区二区三区四区在线播放| 欧美激情1区2区| 日本丰满少妇裸体自慰| 欧美伊人久久久久久久久影院| 一本一道波多野毛片中文在线| 亚洲www视频| 亚洲精品1区| 舐め犯し波多野结衣在线观看| 欧美日韩免费在线视频| 黄色影院在线看| 欧美在线日韩精品| 国产一区二区三区在线观看精品 | 69久久99精品久久久久婷婷| 青草视频在线免费直播| 欧美在线视频二区| 国产传媒一区在线| 亚洲第一网站在线观看| 日韩中文在线中文网在线观看| 1769国产精品视频| 国产精彩免费视频| 亚洲最快最全在线视频| 国产日产精品久久久久久婷婷| 51蜜桃传媒精品一区二区| 国产精品综合| www.av成人| 亚洲香蕉av在线一区二区三区| 久久三级中文| 蜜臀av午夜一区二区三区| 亚洲乱码国产乱码精品精98午夜| 你懂的在线播放| 国产精品久久久久免费| 美女视频黄久久| 精品成人久久久| 久久99精品久久久久久噜噜|