js|編譯|效能
歡迎來到“管理角”這個版,新一期的月刊專欄專註於 WebLogic 伺服器的管理、配置、處理和開發方面。
開闢這個專欄的目的是為了向大家介紹在使用WebLogic Sever時,能普遍用到的非J2EE開發方面的問題。開發人員和管理者同樣會發現這個專欄非常有價值,因為這些文章既適用於開發又適用於最終產品的應用。此外,它很大程度上利用了來自於該領域和工程實驗室的經驗,它提供了對實際問題的詳細解答。
JSP先行編譯的必要性
本月的文章著眼於移除潛在的系統效能瓶頸,它通過解決一個最普通的問題――在伺服器已耗用時間中的JSP (JavaServer Page)編譯的系統開銷問題,這個問題困擾著幾乎所有的J2EE發展計劃。雖然JSP是在J2EE應用範圍內呈現動態HTML視圖的理想選擇,但在某種程度上它們會影響效能,這比錯誤的更令人討厭,給人的第一感覺是該程式很慢。
根據J2EE規範,JSP主要是HTML檔案,在它裡麵包含著Java代碼用來和其他的系統組件進行互動以及動態顯示資訊。規範規定所有的J2EE編譯應用伺服器應當支援JSP,客戶請求一個特定的JSP,將:
● 轉換JSP從HTML格式成為servlet類型的Java類(Java源格式),用簡寫的JSP符號代替完全符合規定的Java文法
● 將新產生的Java源檔案編譯成.class位元組碼形式
● 在新編譯的類上執行適當的介面方法並且對用戶端請求返迴響應。
雖然從發展的觀點來看對於在展示層內管理動態HTML的產生這是最好的途徑,但它影響到伺服器的已耗用時間環境,要求JSP被解析、轉變成Java代碼,並且在它去處理一個特定的用戶端請求之前被編譯。對終端使用者明顯的影響是,一個響應將會被延遲知道給定的JSP檔案被編譯通過。考慮到一個特定的使用者請求可能用到兩個或多個JSP檔案,因此編譯狀態必需的時間增加了很多倍。
對第一個請求一個特定的JSP頁面並且迫使被請求的檔案進行初始編譯的終端使用者,會感覺應用程式很慢並且沒有響應。 雖然這樣的感覺可能存在,但是對於特定的JSP檔案的編譯過程通常在給定的應用伺服器虛擬機器執行個體的生命週期中完成一次。 因此,它對效能總體上的影響被考慮成一種障礙,而不是對應用程式總回應時間的一個嚴重的障礙。然而,在生產環境中為了傳送基於JSP的J2EE應用程式的生產系統,必須克服JSP的缺陷並且對終端使用者進行透明的編譯。
這樣,生產環境如何能受益於JSP檔案,還要避免運行時編譯的效能打擊?答案是簡單的:執行一個一般作為JSP先行編譯的過程。 借用JSP先行編譯,已經被先行編譯的在離線環境中的JSP檔案和他們的編譯結果被部署在生產環境中。如果結果類檔案的先行編譯和部署正確的完成,應用程式伺服器將會為JSP檔案運行先前的編譯類,並且在運行中將不強制對特定的請求進行再編譯。 這樣產生了一種情況,應用程式的操作避免了多餘的編譯開銷,允許系統管理員移除對系統總效能會造成影響的一個已知的瓶頸。
不同的方法論和途徑
沒有人懷疑JSP先行編譯的承諾聽起來令人興奮。 然而,為了要實現這樣的承諾,你必須首先瞭解能夠執行這個技術的不同途徑,以及它們各自優點和缺點。
運行應用程式進行強制先行編譯
用於實現JSP先行編譯最顯而易見的方法是在產品發布前,通過請求在應用程式中的所有可能的JSP頁面,因此編譯在終端使用者訪問網站前完成。它既可以通過第一次人工瀏覽整個網站時完成也可以通過從測試系列應用程式或其他指令碼語言的用戶端(例如LoadRunner 或 SilkPerformer)發動自動請求來實現。 當使用這種方法(可能是所有的JSP先行編譯方法中的最簡單的而又較下策的一個方法)時,他的缺點很快就顯現出來了。也許最大的缺點是很難實現跨叢集環境,在叢集環境中,用該方法對於單一節點的執行個體發送的請求依叢集中的節點數量成倍的增加。而且,當這個叢集是由一個或更多的Web伺服器或硬體負載權衡者來代理時,更難保證在一個叢集的環境中每個伺服器執行個體都進行JSP先行編譯,因為一般沒有方法來搞清代理最初把請求轉到哪個應用伺服器。此外,在應用伺服器每次重啟時,這個方法必須執行,當網站很小時,不能一次實現所有的編譯就會很痛苦。因此,我們不推薦這種JSP先行編譯的方法。
使用編譯工具來實現先行編譯
因為人工執行一個網站應用程式來強制JSP先行編譯在真實的產品環境中是一個較大的缺點,在先行編譯運行期間選擇編譯JSP,使其變成為servlets變得更令人心動。幸運地,WLS提供了二個方法。第一種方法在伺服器啟動部署一個特定的Web應用程式的時候執行先行編譯(declarative先行編譯),第二種方法是命令列Java工具(weblogic.jspc)允許過程在完全離線的情況下處理(程式方式的先行編譯)。兩種方法都有它們的優點,程式方式的先行編譯在兩者中有更靈活的選項,並且提供更讓人無法抗拒的理由來使用它。
DECLARATIVE先行編譯
對於在WLS下公布的先行編譯,一個特定的Web應用程式(獨立的或者作為EAR的一部分)能夠被配置,因此所有的JSP在應用程式部署(伺服器啟動時)和重新部署(運行時)期間裡被先行編譯。對WEB-INF/ weblogic.xml部署描述符要做必要的配置變化,使用先行編譯<jsp-param/>指令,如下:
<weblogic-web-app>
…
<jsp-descriptor>
<jsp-param>
<param-name>precompile</param-name>
<param-value>true</param-value>
</jsp-param>
</jsp-descriptor>
…
</weblogic-web-app>
在一個特定的Web應用程式上進行部署(或重新部署),如果上述的參數被設定成真, WLS 將會在WAR內嘗試先行編譯所有的JSP檔案,在程式中從 Web 應用程式的根目錄下迴圈的運行它的方法( 略過Web-INF) 。以. jsp 或 .JSP為副檔名的檔案都變成了編譯的對象。 被編譯後的檔案被以適當的包目錄結構形式被放置在Web 應用程式的臨時工作目錄下面(預設在Web-INF子目錄中,除非在 weblogic.xml 裡有特別說明)。
這個方法是到目前為止進行JSP先行編譯最方便的途徑(“flick-a-switch” 途徑),他有許多指出來毫無意義的缺點。如果一個錯誤在JSP的編譯期間或在部署(或重新部署) 的時候發生,Web 應用程式的先行編譯將會在例外處暫停。另外,如果在一個特定的Web應用程式裡面有許多JSP檔案的情況,declarative先行編譯顯著的影響著部署時間,阻斷部署直到所有的檔案都被編譯。對於大型的應用程式,當出現數以百計的JSP 檔案以declarative先行編譯被執行的時候,這種部署時間趨向以分鐘來計算 (在某些情況10到15分鐘,其他情況可能更長時間)。設想開始一個伺服器執行個體,在一個特定的Web應用程式周期內進入部署狀態用declarative 先行編譯啟用。如果在應用內有很多的JSP檔案以及部署,接近完成時就已經花費了大量的時間,在編譯期間由於拋出一個例外而突然失敗,當然會引起挫折感。雖然起先看起來比較方便,但declarative 編譯對生產系統管理造成重大的風險,因此應該在經過謹慎的考慮後再使用它。
程式方式的先行編譯
在WLS下最可靠的先行編譯JSP的方法是使用Java命令列,weblogic.jspc,它位於WLS安裝的lib目錄之下的weblogic.jar檔案中。這個工具允許開發人員在發展階段和在部署前解決編譯時間問題的時候編譯需要的JSP檔案。它也為生產系統提供一個有能力實現JSP先行編譯的管理員。這種用法的主要好處是:
● 檔案可以被先行編譯一次然後可以被多次部署。(這不被伺服器執行個體的重複利用所影響)
● 編譯時間的例外可以被預先解決而不影響部署。
● 類可以通過叢集部署。
使用weblogic.jspc的缺點是需要人工幹涉,並且它在開發時併當在JSP檔案變得過時的時候必須被重新運行。然而,考慮到前面的兩個方法的討論,我們幾乎不能將這種不方便當成該方法的一個缺點,因此推薦它作為最可靠和最靈活的機制來實現JSP先行編譯。
執行weblogic.jspc
為了更有效使用weblogic.jspc,你必須首先瞭解它的用法和文法。這篇文章我們將利用WLS6.1 SP2的工具的功能。注意:下面給出的文法和最好的慣例應該應用於WLS 6.1的所有版本以及新的WLS 7.0。
為了調用命令列JSP編譯器(weblogic.jspc),你必須確定下面的內容:
● PATH環境變數必須包含你機器上安裝的J2SE1.3包的二進位目錄(例如,/opt/j2se/1.3.1/sdk/bin 或者c:\sunsoft\j2se\1.3.1\sdk\bin),以獲得JVM運行時的支援。如果你打算使用javac作為你的JSP編譯的Java編譯器,要確定PATH包含全部Java 1.3 的軟體開發套件(SDK)的二進位目錄,並且不僅僅是JRE(Java Runtime Engine,Java已耗用時間引擎),因為沒有編譯器和JRE關聯。 如果你打算使用一個編譯器而不是javac(例如 Jikes),也要為那個編譯器確定在PATH中包含正確的目錄。
● 設定Java系統類別路徑用來包含來自WLS 6.1 SP2 安裝目錄的weblogic.jar檔案,通過在產品庫目錄下預設建立(例如,/opt/bea/wlserver6.1/lib/weblogic.jar或者c:\bea\wlserv -er6.1\lib\weblogic.jar)。此外,請確定在JSP編譯階段中你可能需要的參考類(JAR或類檔案)也在你的類路徑中。
在第一次執行weblogic.jspc之前,你需要測試你的命令列配置是否是按上述配置。它可以通過簡單運行一個WLS版本檢查來完成,使用命令“java weblogic.version”,這個命令應該返回下面的內容:
which should return the following:
WebLogic Server 6.1 SP2 12/18/2001 11:13:46
#154529
WebLogic XML Module 6.1 SP2 12/18/2001
11:28:02 #154529
如果你的輸出和上面的不相似(和你啟動並執行版本相對應),在進行JSP先行編譯前,要重新訪問PATH和類路徑變數將其設定成你的當前命令列環境。
一般的weblogic.jspc的文法如下面給出的:
java weblogic.jspc [options] <jsp files>...
在一個編譯器的單一調用中預設情況下JSP編譯器可以編譯一個JSP檔案或一組JSP檔案,並且可以通過設定命令列選項,編譯器可以以不同的方法工作。下面給出一個例子:
java
weblogic.jspc
-webapp mywebapp
-compiler javac
-compileFlags "-g"
-classpath /u/apps/dist/src/lib.jar
-d .
-package com.slackwerks.mywebapp.jsp
-commentary
-keepgenerated
-k
mywebapp\index.jsp
這篇文章只列舉了一個例子,如果你要想更加瞭解weblogic.jspc如何能在你的環境中使用和管理的話,請參閱www.slackwerks.com/wldj,我們提供了對整套的工作選項,使用的含義以及相關聯問題的討論。
結論
雖然關於JSP先行編譯的問題較多,但許多的途徑可以解決。然而,考慮到上文所說的那些優點和缺點,應該較容易的看出經由weblogic.jspc先行編譯的程式方式是為克服JSP固有的缺點的一個靈活的選項。在開發階段的早期,熟悉該工具將改善生產期間應用程式的管理和效能狀況。