IBM WebSphere 自定義門戶代碼的性能注意事項(xiàng)
性能通常是功能、可維護(hù)性、程序執(zhí)行時(shí)間和內(nèi)存使用間的折衷。本文檔提供了一些編程建議,以使用 IBM? WebSphere? Portal 最大限度地提高門戶應(yīng)用程序組件(如 Portlet、主題和外觀)的性能。
摘自 IBM WebSphere 開發(fā)者技術(shù)期刊。
本文提供了一些常規(guī)指導(dǎo),以創(chuàng)建能夠正常執(zhí)行的 IBM WebSphere Portal 自定義代碼。自定義代碼不僅指 Portlet(雖然它們是最常見的門戶編程模型),也包括 WebSphere Portal 的主題和外觀代碼。由于這些組件均采用與 Portlet 相同的技術(shù)實(shí)現(xiàn),所以很多相同的性能注意事項(xiàng)對(duì)它們也同樣適用。
對(duì)于 Portlet,本文主要集中討論遵循 Java? Portlet 規(guī)范 JSR 168 及 WebSphere Portal 中的對(duì)應(yīng)實(shí)現(xiàn)的標(biāo)準(zhǔn)化 Portlet。本文基于 WebSphere Portal V5.1 或更高版本,不過本文中所給出的準(zhǔn)則和大部分建議永遠(yuǎn)適用,而不受所運(yùn)行的 WebSphere Portal 版本的影響。
本文將說明如何設(shè)置和使用 Porlet 應(yīng)用程序的部署參數(shù)以優(yōu)化門戶和 Portlet 的性能,因?yàn)檫@是創(chuàng)建自定義門戶代碼的最后一步。不過 WebSphere Portal 的總體優(yōu)化(即創(chuàng)建并部署自定義代碼后執(zhí)行的管理操作)將不在本文中討論。另一個(gè)文檔對(duì) WebSphere Portal 性能優(yōu)化進(jìn)行了說明。該文檔與本文檔共同提供了門戶與性能方面不錯(cuò)的參考資料。
本文旨在供參與構(gòu)建門戶應(yīng)用程序并希望提高對(duì)與自定義代碼相關(guān)的潛在性能問題的理解的程序員、設(shè)計(jì)人員和架構(gòu)師使用。
IBM WebSphere Portal 構(gòu)建于 the IBM WebSphere Application Server 產(chǎn)品之上。因此,自定義門戶代碼的編程環(huán)境具有三重特征,其對(duì)應(yīng)的重要含義如下:
-
WebSphere Portal 及其所有組件均為基于 Java 的程序。
因此,總的來說,應(yīng)該遵循編寫高性能 Java 代碼的最佳實(shí)踐。
-
WebSphere Portal 是運(yùn)行于應(yīng)用程序服務(wù)器平臺(tái)上的 J2EE 應(yīng)用程序。
J2EE 包含多線程技術(shù);J2EE 容器通常采用每個(gè)請(qǐng)求一個(gè)線程的方法處理請(qǐng)求負(fù)荷。對(duì)于使用此機(jī)制必然涉及到的任何實(shí)現(xiàn)或性能注意事項(xiàng)都應(yīng)該加以注意。
-
WebSphere Portal 提供了 API 以擴(kuò)展門戶功能。
可以采用很多方法對(duì)任務(wù)進(jìn)行編程。應(yīng)該首先考慮影響性能的差異。
下一部分中將介紹一些關(guān)于門戶編程環(huán)境不同部分的一般性能注意事項(xiàng)。
顯然,本部分并不會(huì)提供處理 Java 性能的全部技術(shù)。我們僅在此處給出在我們認(rèn)為進(jìn)行 WebSphere Portal 開發(fā)時(shí)最有用的相關(guān)事項(xiàng),并提供一些可幫助深入了解 Java 性能的參考資料(請(qǐng)參閱參考資料)。
基本 Java 性能
在這一部分中,我們將討論一些應(yīng)用到大部分 Java 的一般性能項(xiàng)。盡管這些建議可能并不會(huì)帶來大幅度的性能提高,但可以使您對(duì)在開發(fā)階段底層程序執(zhí)行性能的重要性有所認(rèn)識(shí)。
-
當(dāng)需要修改字符串時(shí),使用 java.lang.StringBuffers 實(shí)例,而不要使用 java.lang.String 實(shí)例。
在 Java 中,String 對(duì)象是不可變的,而 StringBuffer 對(duì)象是可變的。無論何時(shí)將文本附加到 String 或從中刪除,實(shí)際上都將創(chuàng)建一個(gè)新對(duì)象,并將舊對(duì)象丟棄。因此我們首選以下的方式:
StringBuffer sb = new StringBuffer("Hello "); sb.append(var).append(" World");
以此為基礎(chǔ)的字符串聯(lián)結(jié)操作:
String s = "Hello" + var + " World";
有時(shí)可以通過設(shè)置 StringBuffer 的初始容量進(jìn)一步提高性能;該類的設(shè)計(jì)使其可以在不能保存全部數(shù)據(jù)時(shí)自動(dòng)擴(kuò)大容量。不過此處有性能損失,因?yàn)?StringBuffer 必須透明地增加其大小和對(duì)數(shù)據(jù)移位。例如,如果將 StringBuffer 作為收集參數(shù)(即將向其添加越來越多的數(shù)據(jù))使用,應(yīng)該在對(duì)其進(jìn)行初始化之前計(jì)算恰當(dāng)?shù)木彌_區(qū)大小,以使其永遠(yuǎn)都不需要增加大小。
-
避免在服務(wù)器端程序中進(jìn)行開銷很大的 I/O 操作。
在 I/O 操作期間至少會(huì)阻塞當(dāng)前線程;如果其他線程也必須等待磁盤,則系統(tǒng)響應(yīng)時(shí)間將會(huì)迅速增大。除非在執(zhí)行日志記錄功能(例如,在記錄異常或站點(diǎn)訪問信息),否則 WebSphere Portal 自己不會(huì)引起任何磁盤訪問。我們將在后面對(duì) I/O 進(jìn)行進(jìn)一步討論。
-
盡可能減少同步代碼塊的數(shù)量和長(zhǎng)度。
synchronized 關(guān)鍵字每次僅允許一個(gè)線程進(jìn)入代碼塊。同步代碼塊所需的執(zhí)行時(shí)間越長(zhǎng),其他線程等待進(jìn)入該代碼塊的時(shí)間就越長(zhǎng)。我們將在后面對(duì)同步進(jìn)行進(jìn)一步討論。
-
避免開銷巨大的計(jì)算和方法調(diào)用。
例如,使用 System.currentTimeMillis() 檢索當(dāng)前時(shí)間信息開銷就相當(dāng)大。如果確實(shí)需要時(shí)間信息,請(qǐng)確定是需要當(dāng)前準(zhǔn)確的時(shí)間,還是(例如)準(zhǔn)確到最近的秒數(shù)就足夠了。如果在代碼路徑中有很多獲取時(shí)間的調(diào)用,但并非一定要毫秒級(jí)的準(zhǔn)確度,可以采用替換方法,即確定請(qǐng)求開始的時(shí)間,然后直接在請(qǐng)求期間使用該信息。
-
限制異常的使用。
通常,應(yīng)將 Java 中的異常用于指示錯(cuò)誤情況。不要使用異常指示操作成功,這主要是因?yàn)?JVM 創(chuàng)建異常堆棧跟蹤非常費(fèi)時(shí),而且在 WebSphere Portal 系統(tǒng)中的跟蹤深度會(huì)很深。
-
使用 Java Reflection API 時(shí)需要謹(jǐn)慎。
此 API 為動(dòng)態(tài)代碼執(zhí)行增加了功能強(qiáng)大的選項(xiàng),但就方法執(zhí)行時(shí)間而言,獲得這種靈活性會(huì)導(dǎo)致嚴(yán)重的性能損失。通常,應(yīng)盡力避免在門戶代碼中使用 Java Reflection API。不過,如果有必要進(jìn)行反射調(diào)用,則應(yīng)盡量將其放置在初始方法中,以使其在每個(gè)請(qǐng)求期間都不會(huì)執(zhí)行。
內(nèi)存使用和垃圾生成
雖然內(nèi)存對(duì)于 Java 客戶機(jī)軟件通常不是一個(gè)突出的性能問題,但對(duì)于 J2EE 應(yīng)用程序卻是一個(gè)主要問題,這主要是因?yàn)槠髽I(yè)應(yīng)用程序通常由很多用戶同時(shí)訪問。為了使應(yīng)用程序服務(wù)器高效運(yùn)行,可用資源(包括內(nèi)存、CPU 和帶寬)均由客戶機(jī)的請(qǐng)求共享。我們要提到三個(gè)主要內(nèi)存問題:
-
盡可能減少臨時(shí)對(duì)象的數(shù)量。
這意味著要盡可能地重用對(duì)象,而不要太頻繁地創(chuàng)建新對(duì)象實(shí)例。創(chuàng)建的對(duì)象越多,JVM 垃圾回收器就必須更頻繁地回收內(nèi)存并會(huì)(至少部分)中斷此時(shí)的請(qǐng)求處理。創(chuàng)建許多對(duì)象還容易增加堆碎片,而這會(huì)導(dǎo)致出現(xiàn)更多的垃圾回收周期。例如,不要過早創(chuàng)建對(duì)象:
String logData = "Parameter 1: " + param1; if (logger.isLogging(DEBUG)) { logger.log(logData); }
在本例中,僅在對(duì)條件進(jìn)行求值之后才應(yīng)創(chuàng)建 logData。緩存和對(duì)象池技術(shù)均可以減少臨時(shí)對(duì)象的創(chuàng)建。若要識(shí)別代碼中最常導(dǎo)致內(nèi)存分配問題的部分,請(qǐng)參閱工具。
-
將內(nèi)存永久占有的情況保持為最低。
不要將太多信息讀入內(nèi)存中;而要使用緩存保存重要的信息。有時(shí)可以針對(duì)一條信息更改數(shù)據(jù)類型。例如,數(shù)據(jù)信息可以保存在 java.util.Date 對(duì)象內(nèi)或 long 變量中。與基元數(shù)據(jù)類型相比,對(duì)象通常更大,處理速度也會(huì)有些慢。它可能會(huì)依賴于鄰近的 API 和數(shù)據(jù)類型首選的數(shù)據(jù)結(jié)構(gòu)。通常,內(nèi)存占用率越高,就會(huì)導(dǎo)致垃圾回收率更高,請(qǐng)求處理期間暫停的次數(shù)也會(huì)增加。
-
檢查應(yīng)用程序以確定是否存在內(nèi)存泄漏。
內(nèi)存泄漏通常出現(xiàn)在 Java 集合類中。例如,如果有一個(gè) java.util.Map,在特定情況下,會(huì)將數(shù)據(jù)添加到映射中,但卻永遠(yuǎn)不從其中刪除。內(nèi)存泄漏會(huì)導(dǎo)致 Java 堆保留的內(nèi)存使用越來越大,隨著時(shí)間的增加,垃圾回收器能釋放的內(nèi)存會(huì)越來越少。這樣,會(huì)導(dǎo)致垃圾回收更頻繁,而最終將使門戶系統(tǒng)停止響應(yīng)。而更糟糕的是,通常僅在長(zhǎng)時(shí)間運(yùn)行的測(cè)試中才能發(fā)現(xiàn)內(nèi)存泄漏,不過可以使用各種工具幫助進(jìn)行此類分析(請(qǐng)參閱工具)。
性能和可擴(kuò)展性代碼設(shè)計(jì)
設(shè)計(jì)和開發(fā)可伸縮性代碼時(shí),需要記住很多事項(xiàng)。其中最為重要的三方面是:緩存、對(duì)象池和信息預(yù)提取:
-
緩存,存儲(chǔ)已經(jīng)計(jì)算得到的結(jié)果。
例如,可以從后端系統(tǒng)檢索信息,但不將每個(gè)可能的對(duì)象均從存儲(chǔ)區(qū)復(fù)制到內(nèi)存中,而僅加載其中的小部分,將其放置在緩存中。這樣,該信息就對(duì)稍后的引用可用(可能在后續(xù)的另一請(qǐng)求中使用,甚至供另一個(gè)用戶使用)。
緩存始終采用對(duì)象映射的形式,具有大小上限。緩存還必須知道不可能再次請(qǐng)求某個(gè)內(nèi)容的情況,以便在合適時(shí)從緩存中將其刪除。這種排除操作通常由“生存時(shí)間”(TTL) 或“最近最少使用”算法確定。而且使用緩存的客戶機(jī)不能保證將成功從緩存檢索對(duì)象;必須首先檢查對(duì)象是否存在,如果沒有找到,則將創(chuàng)建該對(duì)象:
Mail mail = myCache.get("myMail"); if (mail == null) { mail = readMailInformation(); myCache.put("myMail", mail) ; } ...
(在某些情況下,特定于應(yīng)用程序的緩存可以設(shè)計(jì)為從對(duì)客戶機(jī)透明的某個(gè)數(shù)據(jù)源查找所需的數(shù)據(jù)。)
-
使用對(duì)象池限制特定類的實(shí)例的數(shù)量。
每個(gè)請(qǐng)求都需要特定類的實(shí)例,但此對(duì)象并不(也不應(yīng))需要在每個(gè)請(qǐng)求中重新創(chuàng)建。在對(duì)象創(chuàng)建和初始化開銷很大的情況下,尤其是這樣。客戶機(jī)可以不接受性能命中,而從池中請(qǐng)求對(duì)象,然后在用完之后將其返回池中。
PooledObject po = myPool.get(); ... // use the PooledObject ... myPool.put(po);
-
對(duì)象池的一種簡(jiǎn)單形式就是將對(duì)象規(guī)范化。
這意味著對(duì)象的所有不同實(shí)例在程序初始化階段創(chuàng)建,將在隨后重用和引用。java.lang.Boolean 類就是已規(guī)范化對(duì)象的例子。只需要有兩種不同的 Boolean 對(duì)象即可(最好能作為常數(shù)訪問)。同樣,也可使其他對(duì)象使用一組固定的只讀內(nèi)部狀態(tài)。
-
只提取當(dāng)前希望處理的數(shù)據(jù),而不提取多余的數(shù)據(jù)。
例如,在 Portlet 中,可以提供一個(gè)電子郵件列表;該 Porlet 將顯示主題、日期、發(fā)件人和其他重要信息。當(dāng)用戶選擇了特定的電子郵件時(shí),將顯示該郵件的正文。在從 Porlet 中選擇特定的項(xiàng)之前,不需要正文,因此提前檢索正文將浪費(fèi)執(zhí)行時(shí)間和內(nèi)存資源。這種模式在很多情況下都適用。總的原則是,僅計(jì)算和檢索對(duì)于當(dāng)前請(qǐng)求和響應(yīng)有直接意義的信息。
IBM WebSphere Application Server 是 J2EE 實(shí)現(xiàn),WebSphere Portal 就構(gòu)建于其上。由于本部分中很多性能注意事項(xiàng)適用于 J2EE 運(yùn)行時(shí)上下文,所以其中的很多信息除了適用于 WebSphere Application Server 之外,也適用于其他應(yīng)用程序服務(wù)器和 J2EE 應(yīng)用程序。下面所列出的項(xiàng)目在此處只進(jìn)行了簡(jiǎn)單概述,將在后面進(jìn)行更為詳細(xì)的說明。有關(guān)更多的一般性討論,請(qǐng)參閱參考資料。
J2EE 標(biāo)準(zhǔn)
J2EE 標(biāo)準(zhǔn)規(guī)范包含了大量與性能相關(guān)的事項(xiàng):
-
應(yīng)當(dāng)使用初始方法計(jì)算所有后面將用到且不會(huì)發(fā)生更改的內(nèi)容(很多 J2EE 資源都可以使用初始方法,Portlet 也可以使用此類方法)。例如,數(shù)據(jù)源等普通資源的 JNDI 程序應(yīng)該僅在初始化時(shí)執(zhí)行一次。此外,也應(yīng)該僅在 Portlet 初始化期間讀取一次來自特定只讀文件的數(shù)據(jù)。可以對(duì) Portlet 服務(wù)方法進(jìn)行掃描,以發(fā)現(xiàn)所有對(duì)每個(gè)請(qǐng)求執(zhí)行相同操作的代碼,將其移動(dòng)到初始方法中,以降低該服務(wù)方法的運(yùn)行時(shí)開銷。
-
EJB 和會(huì)話是 J2EE 中非常重要且功能強(qiáng)大的概念,但如果使用不當(dāng),二者均可能導(dǎo)致性能損失。例如,應(yīng)用程序不應(yīng)將過多的數(shù)據(jù)放置到會(huì)話中,從而減少服務(wù)器的內(nèi)存占用并更快速方便地保持會(huì)話。關(guān)于 EJB 組件,應(yīng)該熟悉與遠(yuǎn)程調(diào)用和本地調(diào)用等相關(guān)的不同持久類型。EJB 可以使用的某些功能會(huì)帶來大的性能損失。
WebSphere Application Server
WebSphere Application Server 產(chǎn)品提供了各種功能,以幫助開發(fā)人員和架構(gòu)師設(shè)計(jì)高性能系統(tǒng)。(請(qǐng)參閱參考資料中給出的 WebSphere Application Server 信息中心和 WebSphere Business Integration Server Foundation 信息中心)。
- 正如前面所提到的,創(chuàng)建數(shù)據(jù)庫連接的開銷非常大。按照 J2EE 標(biāo)準(zhǔn)中的定義,應(yīng)用程序服務(wù)器可以提供連接池機(jī)制,從而無需為每個(gè)傳入請(qǐng)求重新創(chuàng)建連接。WebSphere Application Server 使用一些額外的性能 Helper 提供這樣的連接池機(jī)制,相當(dāng)于頻繁執(zhí)行的 SQL 語句的語句緩存。不過,如果完成數(shù)據(jù)庫交互后沒有及時(shí)返回連接,將回導(dǎo)致相當(dāng)長(zhǎng)時(shí)間內(nèi)連接對(duì)其他請(qǐng)求不可用。通過使用 WebSphere Application Server 管理控制臺(tái),可以將連接池作為 JDBC 數(shù)據(jù)庫的數(shù)據(jù)源屬性進(jìn)行控制,并能進(jìn)行定義,例如可以定義連接池中的最少連接數(shù)和最大連接數(shù)。(請(qǐng)參閱 WebSphere Application Server 信息中心以了解詳細(xì)信息。)
下面所給的示例演示了多個(gè)請(qǐng)求對(duì)連接進(jìn)行重用。在本例中,可以使用 JDBC 連接池和利用 Application Server 提供的語句緩存:
. . . public class IDontCare extends GenericPortlet { private javax.sql.DataSource ds; public void init() throws javax.portlet.PortletException { try { Hashtable env = new Hashtable(); env.put( Context.INITIAL_CONTEXT_FACTORY, "com.ibm.ejs.ns.jndi.CNInitialContextFactory" ); Context ctx = new InitialContext( env ); ds = (javax.sql.DataSource)ctx.lookup( "jdbc/MYSHOES" ); ctx.close(); } catch (Exception any) { // handle exceptions here . . . } } . . . public void processAction ( ActionRequest request, ActionResponse response ) throws PortletException, IOException { . . . try { Connection con = null; ResultSet rs = null; PreparedStatement pStmt = null; con = ds.getConnection ( dbuser, dbpasswd ); pStmt = con.prepareStatement( "select * from myscheme.size_of_shoes"); rs = pStmt.executeQuery(); . . . // release the resource when it is no longer used if (pStmt != null) pStmt.close(); if (con != null) con.close(); } catch (Exception any) { // handle exception here . . . } } }
-
WebSphere Application Server 還支持對(duì)象池的常規(guī)概念,每個(gè)對(duì)象池均具有池管理器,從而為不同類類型提供對(duì)象池訪問。可以查詢此類對(duì)象池以獲得類類型實(shí)例,如前面關(guān)于池技術(shù)的示例中所述。請(qǐng)參閱 WebSphere Business Integrator Server Foundation 信息中心以獲得詳細(xì)信息。
-
WebSphere Application Server 還提供了“一般用途”的緩存。在管理控制臺(tái)中,可以定義緩存實(shí)例,應(yīng)用程序可以使用這些緩存實(shí)例存儲(chǔ)、檢索和共享數(shù)據(jù)。與缺省共享動(dòng)態(tài)緩存(門戶使用其緩存對(duì)象)不同,緩存實(shí)例僅可由知道其 JNDI 名稱的應(yīng)用程序訪問。DistributedMap 類是應(yīng)用程序所使用的編程接口,該類允許應(yīng)用程序從緩存實(shí)例獲得對(duì)象和將對(duì)象放置到其中,并可以使其失效。請(qǐng)參閱 WebSphere Business Integrator Server Foundation 信息中心以獲得詳細(xì)信息 [8] (LINK)。
如果 Portlet 使用緩存實(shí)現(xiàn),它們應(yīng)該在其初始階段查找或?qū)嵗粋€(gè)緩存實(shí)例,并保持該緩存的引用,以使緩存條目具有可能比單個(gè)請(qǐng)求長(zhǎng)的生存期。在處理 Portlet 的操作和呈現(xiàn)階段時(shí),可以將條目放置到緩存中,并從中進(jìn)行檢索。Portlet 實(shí)現(xiàn)需要確保如果使用特定鍵查詢時(shí),緩存沒有返回?cái)?shù)據(jù),應(yīng)有適當(dāng)?shù)暮蠖嗽L問和緩存進(jìn)行更新處理。另外,還要注意,為了實(shí)現(xiàn)設(shè)計(jì)的特定功能,可能需要限定鍵在緩存中的范圍(如,基于用戶會(huì)話)。緩存通常為自我管理的單元,根據(jù)緩存實(shí)現(xiàn),可以排除條目或使其失效。請(qǐng)注意,出于同樣的原因,緩存并不適合在多段代碼間進(jìn)行信息通信。緩存還應(yīng)該維護(hù)一個(gè)合理的大小上限,以避免自定義代碼中內(nèi)存的過度使用。
WebSphere Portal 支持兩種不同的 Portlet API:
- IBM Portlet API,該 API 對(duì) Servlet 進(jìn)行擴(kuò)展。
- JSR 168 Portlet API,該 API 由 Java Community Process (JCP) 定義。
在本文中,我們將重點(diǎn)討論 JSR 168 Portlet API。
WebSphere Portal 提供了各種接口,用于將 Portlet 集成到 WebSphere Portal 環(huán)境中。因此,應(yīng)該謹(jǐn)慎設(shè)計(jì) Portlet,以充分利用各種門戶功能。請(qǐng)確保采用最佳實(shí)踐(請(qǐng)參閱參考資料中列出的最佳實(shí)踐),以應(yīng)用恰當(dāng)?shù)?WebSphere Portal API。
在本部分中,我們將討論與主題和外觀編程以及 Portlet 開發(fā)相關(guān)的性能主題。
JavaServer Page (JSP) 是 Portlet 編程的基礎(chǔ)之一。在大多數(shù) Portlet 中,JSP 通過使用 Model View Controller (MVC) 作為視圖組件使用。JSP 由 HTML(或其他標(biāo)記語言)組合和 Java 代碼組成;在大多數(shù) HTML 中,它們的處理輸出也是標(biāo)記語言。其最簡(jiǎn)單的形式中,JSP 不包含任何 Java 代碼,但僅包含自定義標(biāo)記,調(diào)用這些標(biāo)記以執(zhí)行非 HTML 操作。(相反地,JSP 文件中也可能不包含任何 HTML 內(nèi)容)。
- 在第一次訪問 JSP 文件時(shí),將對(duì)文件進(jìn)行分析,將其轉(zhuǎn)換為常規(guī) Java Servlet 源文件,該源文件將隨后編譯為字節(jié)代碼。因此,由于后續(xù)的兩次轉(zhuǎn)換(從 JSP 到 Java 源再到字節(jié)代碼),第一次請(qǐng)求 時(shí)通常比較緩慢,但對(duì)于之后的所有請(qǐng)求,JSP 將同任何其他 Servlet 一樣工作。
這與其他生成 HTML 內(nèi)容的方法(XML 和 XSLT)不一樣。使用其他方法時(shí),對(duì)于每次請(qǐng)求都必須解析 XML 和應(yīng)用樣式表轉(zhuǎn)換。只有很好地緩存了結(jié)果而不需每次請(qǐng)求都重新運(yùn)行轉(zhuǎn)換,才能保證性能。因此,從性能的角度出發(fā),JSP 應(yīng)該優(yōu)于 XML/XSLT。此外,門戶基礎(chǔ)設(shè)施還針對(duì) JSP 進(jìn)行了優(yōu)化,允許方便地?cái)U(kuò)展以支持其他標(biāo)記、語言和瀏覽器。
-
應(yīng)用程序服務(wù)器執(zhí)行 JSP 的方式與執(zhí)行常規(guī) Servlet 類似。不過,JSP 編譯產(chǎn)生的 Servlet 包含生成的代碼,這些代碼的性能優(yōu)化程度稍遜于手動(dòng)編寫的代碼。如果性能對(duì)于特定 JSP 非常重要,而使用生成的代碼又不能達(dá)到目的,請(qǐng)考慮手動(dòng)將標(biāo)記編寫到輸出流中。
-
JSP 中的 Java 代碼片斷稱為 Scriptlet。由于 JSP 將轉(zhuǎn)換為 Java 源代碼,因此使用 Scriptilet 并沒有真正的性能損失。WebSphere Application Server 的最新版本中的某些優(yōu)化將在 JSP 文件不包含任何 Scriptlet 的情況下應(yīng)用。通常,不應(yīng)將 Scriptlet 代碼放置到 JSP 中,而應(yīng)使用標(biāo)記完成這些任務(wù)。
-
JSP 中可以包含其他 JSP。這意味著單個(gè) JSP 不必對(duì)請(qǐng)求作出全部響應(yīng);可以將響應(yīng)拆分為多個(gè) JSP,在父 JSP 中包括其他 JSP。有兩種包含方式,靜態(tài)包含和動(dòng)態(tài)包含:
-
靜態(tài) JSP 包含在編譯時(shí)解析。JSP 編譯器會(huì)包含所引用的文件,而不包含 include 語句。此選項(xiàng)通常非常快,完全不會(huì)增加運(yùn)行時(shí)開銷。
<%@ include file="include2.jsp" %>
-
動(dòng)態(tài) JSP 包含在運(yùn)行時(shí)解析,開銷并不小。就垃圾生成和執(zhí)行時(shí)間而言,解析要調(diào)度的正確 JSP 開銷非常大。例如(在 JSP 中):
<jsp:include page="include2.jsp" flush="true" %>
JSP 中的動(dòng)態(tài)包含在通過 Servlet 代碼包含其他文件時(shí)使用如下語句:
javax.servlet.RequestDispatcher
因此,只要有可能,應(yīng)該盡量使用靜態(tài)包含。動(dòng)態(tài)包含提供了最高的靈活性,但如果使用過于頻繁,會(huì)帶來巨大的性能開銷。
-
Enterprise JavaBean (EJB) 定義了一個(gè)基于組件的體系結(jié)構(gòu),用于構(gòu)建可擴(kuò)展的分布式多用戶業(yè)務(wù)應(yīng)用程序。EJB 組件設(shè)計(jì)用于封裝業(yè)務(wù)邏輯,并同時(shí)將所有的復(fù)雜性隱藏在 Bean 和內(nèi)置 EJB 容器服務(wù)后。
對(duì)企業(yè)應(yīng)用程序頻繁使用的各種功能的支持會(huì)帶來一定的性能開銷,在使用 EJB 時(shí)需要加以考慮。
-
Portlet 可以通過 JNDI 查詢包含 EJB 引用,而 JNDI 查詢?cè)谛阅芊矫骈_銷很大。例如,如果 Portlet 并不緩存對(duì) EJB 主接口的引用,則每個(gè)對(duì) EJB 的邏輯引用需要兩次遠(yuǎn)程調(diào)用:一個(gè)調(diào)用命名服務(wù),另一個(gè)調(diào)用實(shí)際的對(duì)象。為了改進(jìn)這種情況,請(qǐng)使用緩存技術(shù)以減少或消除對(duì) EJB 主引用的重復(fù)查詢。
-
EJB 組件將公開遠(yuǎn)程接口和本地接口。依賴于位置的 EJB 將使用遠(yuǎn)程接口。方法參數(shù)和返回值將在 RMI-IIOP 上序列化,并由值返回。遠(yuǎn)程方法必須設(shè)計(jì)為能夠根據(jù) API 的使用模式滿足數(shù)據(jù)需求。請(qǐng)使用 API 中的適合接口的使用情況的方法和數(shù)據(jù)類型粒度,以盡可能減少序列化開銷。
-
盡可能減少遠(yuǎn)程調(diào)用的數(shù)量,以減少由于代碼路徑中的遠(yuǎn)程調(diào)用帶來的系統(tǒng)開銷。使用會(huì)話 Bean 作為遠(yuǎn)程外觀使用,對(duì)復(fù)雜交互進(jìn)行包裝,并減少 Portlet 和域?qū)ο箝g的遠(yuǎn)程調(diào)用。直接訪問遠(yuǎn)程實(shí)體 Bean 的 Portlet 通常會(huì)導(dǎo)致多個(gè)遠(yuǎn)程方法調(diào)用。如果在此環(huán)境中使用實(shí)體 Bean,請(qǐng)避免給予其遠(yuǎn)程接口。作為外觀的會(huì)話 Bean 將通過其本地接口訪問實(shí)體 Bean,從其收集數(shù)據(jù),然后將此信息返回發(fā)出調(diào)用的應(yīng)用程序。
當(dāng)發(fā)出調(diào)用的客戶機(jī)(如會(huì)話外觀)與被調(diào)用的 EJB 共享同一個(gè)容器時(shí),本地接口的概念將會(huì)有效果。使用本地接口可以消除分布式對(duì)象協(xié)議的系統(tǒng)開銷,從而降低進(jìn)程間通信開銷。本地調(diào)用并不會(huì)通過通信層,所有對(duì)象均可以通過引用傳遞。
-
EJB 容器支持的事務(wù)管理也可以影響性能。開發(fā)了 EJB 后,程序員必須設(shè)置定義各種特征(如 EJB 的事務(wù)支持和隔離級(jí)別)的部署描述符。如果不需要事務(wù),請(qǐng)將事務(wù)類型設(shè)置為 NotSupported。
-
事務(wù)隔離級(jí)別是基礎(chǔ)數(shù)據(jù)庫將已更改但尚未提交的數(shù)據(jù)向其他事務(wù)公開的程度。為了獲得最佳的性能,請(qǐng)使用自由隔離級(jí)別。不過,讓其事務(wù)看到未提交的數(shù)據(jù)可以帶來意料之外的副作用,如更新沖突和讀取不一致等。有關(guān)如何設(shè)置隔離級(jí)別的說明,請(qǐng)參閱 WebSphere Application Server V5.1.x 信息中心。
請(qǐng)參閱 IBM 白皮書 WebSphere Application Server Development 性能和擴(kuò)展性最佳實(shí)踐和 IBM 紅皮書 IBM WebSphere V5.1 性能、擴(kuò)展性和高可用性 WebSphere 手冊(cè)系列,以獲得其他建議以及關(guān)于每個(gè)建議的相關(guān)理由。
標(biāo)記大小指從門戶服務(wù)器傳輸?shù)娇蛻魴C(jī)的完全呈現(xiàn)門戶頁面的字節(jié)數(shù)量。從門戶服務(wù)器的角度來看,最重要的部分是包含結(jié)果標(biāo)記的 HTML 頁面的大小。也必須將其他文件(如樣式表、圖像或 JavaScript)傳輸?shù)娇蛻魴C(jī)。由于靜態(tài)文件通常保存在 HTTP 服務(wù)器或代理緩存上的門戶系統(tǒng)之外,所以,此處我們將主要討論“真正的”HTML 標(biāo)記大小。
到底出于什么原因非得關(guān)注標(biāo)記大小呢?在公司的內(nèi)部網(wǎng)內(nèi),網(wǎng)絡(luò)帶寬的問題可能會(huì)少一些,但如果用戶通過調(diào)制解調(diào)器或其他低帶寬網(wǎng)絡(luò)連接到門戶,大型 HTML 響應(yīng)很長(zhǎng)的下載時(shí)間可能會(huì)令人非常受不了。
讓我們進(jìn)行一個(gè)簡(jiǎn)單的計(jì)算。假設(shè)服務(wù)器或集群每秒鐘最多能處理 100 個(gè)請(qǐng)求。HTML 頁面大小應(yīng)該為 100KB,這個(gè)值雖然看著很大,但如果在頁面上有復(fù)雜的主題和若干個(gè) Portlet,就很容易達(dá)到這個(gè)大小。對(duì)于服務(wù)器,這意味著必須提供約 10MB/sec 的速度(100 KB * 100 頁面/秒)。而這個(gè)值是 100MB 的網(wǎng)絡(luò)可以處理的最大通信流量。(以太網(wǎng)不可能百分之百地支持其 100MB/sec 的速度,且傳入通信流量也不容忽視。對(duì)于通過 56K 調(diào)制解調(diào)器連接到門戶的用戶,每個(gè)頁面的下載時(shí)間應(yīng)在 15 秒的時(shí)間范圍內(nèi)!)
多大能稱為太大?這個(gè)問題通常很難回答。不過,每個(gè) HTML 頁面的大小超過 100KB 可能就太大了。另外,還要記住,較小的設(shè)備對(duì)其可以處理的每個(gè)請(qǐng)求的標(biāo)記大小有一定的限制。
構(gòu)成標(biāo)記大小的主要內(nèi)容是主題和 Portlet 輸出。由于所有門戶 JSP 均可自定義,所以可以改變標(biāo)記的在終端的緊湊程度。要限制標(biāo)記大小,可以采取以下措施:
-
在 JSP 中使用 JSP 注釋,而不是 HTML 注釋。
JSP 編譯器將刪除窗體注釋 <%-- ... --%>,而保留窗體注釋 <!-- ... -->并將其通過網(wǎng)絡(luò)傳輸。
-
盡量減少 JSP 源文件中的空白、制表符和分行符,因?yàn)?JSP 編譯器將會(huì)保留這些內(nèi)容。
這可能會(huì)降低代碼的可讀性。這些內(nèi)容可以幫助開發(fā)布局良好的代碼,但在 JSP 文件應(yīng)用到生產(chǎn)環(huán)境前,將使用工具對(duì)其進(jìn)行處理,除去其格式設(shè)置。
-
盡量避免多次向客戶機(jī)發(fā)送相同的信息。
例如,樣式定義應(yīng)當(dāng)放入獨(dú)立的 CSS 文件中。JavaScript 代碼也應(yīng)如此。而且,由于這些獨(dú)立的文件通常不會(huì)更改,因此可以將其緩存在瀏覽器或代理緩存中,從而進(jìn)一步減少網(wǎng)絡(luò)通信流量。
-
如果您的環(huán)境設(shè)置為支持壓縮,還可以使用 HTTP 壓縮將壓縮過的標(biāo)記發(fā)送到的客戶機(jī)。
請(qǐng)參考 Web 服務(wù)器和客戶機(jī)的文檔,以獲得詳細(xì)信息。
日志通常最終會(huì)涉及到對(duì)硬盤寫入。從性能的角度而言,任何與磁盤頻繁進(jìn)行交互的內(nèi)容都是潛在的大開銷操作,因此,最好盡量減少在生產(chǎn)環(huán)境中使用 Java I/O 庫。由于通常通過使用某些 Java 編程之下的本機(jī)庫提供 I/O,因此會(huì)有一定的缺省系統(tǒng)開銷。System.out.println 之類的操作在文件 I/O 期間會(huì)對(duì)處理進(jìn)行同步,這將對(duì)性能造成很大的影響。
在開發(fā)和測(cè)試模式中,可能希望所有日志記錄和調(diào)試功能均為活動(dòng)狀態(tài),因?yàn)檫@些功能對(duì)于發(fā)現(xiàn)錯(cuò)誤非常重要。在生產(chǎn)環(huán)境中部署應(yīng)用程序時(shí),讓各種日志功能均處于打開狀態(tài)并非可行的選擇。最佳實(shí)踐應(yīng)是對(duì)日志語句加以保護(hù),使其僅在出錯(cuò)和進(jìn)行調(diào)試的情況下打開。可以通過使用一個(gè)最終的 Boolean 變量實(shí)現(xiàn)此功能,當(dāng)將其值設(shè)置為 false 時(shí),可以有效地指示編譯器進(jìn)行優(yōu)化,不再檢查和執(zhí)行日志記錄代碼:
|
Java 語言提供了兩種流:讀取器/寫入器和輸入/輸出:
- 讀取器和寫入器是在 I/O 操作中支持 unicode 字符的高級(jí)接口。
- 輸入/輸出流提供非常低的級(jí)別(字節(jié)級(jí))的數(shù)據(jù)訪問機(jī)制。
讀取器/寫入器有性能開銷,因?yàn)樗鼈冎荚谟糜谧址鳎視?huì)在后臺(tái)將數(shù)據(jù)編碼為字節(jié)。只要希望操作二進(jìn)制數(shù)據(jù),就應(yīng)該使用輸入/輸出流。
為了盡可能提高 I/O 性能,應(yīng)該對(duì)讀取和寫入操作進(jìn)行緩存。如果希望寫入大量來自 Portlet 的數(shù)據(jù),通常最好采用對(duì)已緩存的數(shù)據(jù)進(jìn)行部分刷新的方式,而不采用對(duì)全部數(shù)據(jù)一次性刷新的方式。另一方面,不要太頻繁地刷新緩沖區(qū)。
用于協(xié)調(diào)對(duì)共享對(duì)象的訪問的 Java 機(jī)制稱為同步。同步語句一次僅允許一個(gè)線程進(jìn)入代碼塊。
-
在 Portlet 的生存期中,容器會(huì)將不同線程中的服務(wù)請(qǐng)求發(fā)送到單個(gè) Portlet 實(shí)例。請(qǐng)避免在 Portlet 中進(jìn)行同步,因?yàn)橥接泻艽蟮男阅苡绊懀和綍?huì)減少并發(fā),因?yàn)樵谕綁K中一次僅允許運(yùn)行一個(gè)線程,所有并發(fā)的線程都要進(jìn)行排隊(duì)。另外,Java 虛擬機(jī)會(huì)使用監(jiān)視器以支持同步,管理這些監(jiān)視器也有性能開銷。除了性能影響之外,還可能出現(xiàn)死鎖,而這可能導(dǎo)致單個(gè) Portlet 凍結(jié),或者甚至更糟,導(dǎo)致整個(gè)門戶凍結(jié)。由于監(jiān)視器不支持進(jìn)行任何死鎖處理,因此程序員應(yīng)負(fù)責(zé)防止死鎖的出現(xiàn)。
-
在有必要進(jìn)行同步的場(chǎng)合下,應(yīng)該盡量縮小同步代碼塊。準(zhǔn)確地識(shí)別哪些代碼真正需要同步并盡可能少地進(jìn)行同步,這非常重要。如果同步代碼塊不夠小,應(yīng)該對(duì)代碼進(jìn)行分析,對(duì)其重構(gòu),以使所有可以異步運(yùn)行的代碼均位于同步代碼塊之外。
-
某些 Java J2SE 功能會(huì)間接地使用同步。Java 集合類(如 Vector 或 Hashtable)都是全面同步的。即使在單線程環(huán)境中 Java 程序也會(huì)有與線程同步相關(guān)的開銷。Java 1.2 引入的較新的集合(如 ArrayList)并不進(jìn)行同步。這就提供了對(duì)數(shù)據(jù)更快的訪問。在需要線程安全的情況下,請(qǐng)使用線程安全視圖。線程安全視圖是包裝類,該類增加了同步標(biāo)準(zhǔn)集合方法的功能。集合類的工廠方法將返回線程安全的集合,該集合由特定的集合類型的實(shí)例支持:
List list = Collections.sychronizedList(new ArrayList());
-
另一個(gè)非直接同步的例子就是 Java I/O 庫。請(qǐng)盡可能少地使用 Java I/O 庫方法(例如 System.out.println()),以減少不必要的性能開銷。
-
不要從 Portlet 生成非托管線程。當(dāng)前 J2EE 強(qiáng)烈建議不要試圖在容器生成新線程。實(shí)際上,J2EE 規(guī)范 6.2.1 編程限制指出:
“如果應(yīng)用程序組件包含的功能與 J2EE 系統(tǒng)基礎(chǔ)結(jié)構(gòu)所提供的功能相同,則會(huì)存在功能沖突和管理混亂。例如,……以管理線程……”
不要試圖生成新線程的一個(gè)實(shí)際原因是因?yàn)樾戮€程對(duì) J2EE 上下文沒有完全訪問權(quán)限。而且,新創(chuàng)建的非托管線程會(huì)妨礙 WebSphere Portal 實(shí)現(xiàn)穩(wěn)定的、優(yōu)化的可擴(kuò)展運(yùn)行時(shí)環(huán)境。因此,請(qǐng)使用 WebSphere Application Server 中的異步 Bean 功能(請(qǐng)參閱 WebSphere Application Server Enterprise V5 和編程模型擴(kuò)展 WebSphere 手冊(cè)系列)。異步 Bean 是一個(gè) Java 對(duì)象或 Enterprise Bean,能夠使用 J2EE 上下文提交在獨(dú)立線程(異步)運(yùn)行的代碼。
Portlet 編程模型允許開發(fā)人員創(chuàng)建特定類型的 Web 應(yīng)用程序,此類應(yīng)用程序可以作為客戶機(jī)瀏覽器中若干此類應(yīng)用程序的聚合視圖的一部分。在 WebSphere Portal 中,此類應(yīng)用程序不僅能共存在一個(gè)頁面(即聚合視圖)上,還能在構(gòu)造該頁面時(shí)彼此進(jìn)行通信。因此,Portlet 的實(shí)現(xiàn)可以影響頁面的總體性能;例如,如果特定的“關(guān)鍵”Portlet 駐留在頁面上,則值得花精力在同一個(gè)頁面上實(shí)現(xiàn)一些其他的關(guān)鍵性能 Portlet。
在實(shí)際的門戶中,完全自我依賴的 Portlet 非常少見,因?yàn)殚T戶通常用作網(wǎng)站的附加內(nèi)容或幫助工具。此類 Portlet 應(yīng)僅在其本地代碼執(zhí)行路徑中優(yōu)化,不應(yīng)對(duì)允許的門戶系統(tǒng)帶來太多的負(fù)荷。
Portlet 更為典型的用戶就是提供需要訪問其他數(shù)據(jù)源或事務(wù)系統(tǒng)的應(yīng)用程序功能,除了 Portlet 的原始執(zhí)行系統(tǒng)之外,這些數(shù)據(jù)源或事務(wù)系統(tǒng)也需要執(zhí)行資源。數(shù)據(jù)可能會(huì)從網(wǎng)絡(luò)上的其他后端系統(tǒng)檢索或存儲(chǔ)到其中。需要在總體系統(tǒng)設(shè)計(jì)中考慮在后端系統(tǒng)上可能出現(xiàn)的事務(wù)長(zhǎng)度、隔離級(jí)別以及數(shù)據(jù)鎖定。
請(qǐng)注意,單個(gè) Portlet 可能不是后端系統(tǒng)的唯一客戶機(jī)。事實(shí)上,在實(shí)際使用中,會(huì)有很多客戶機(jī)連接到此類系統(tǒng),甚至單個(gè) Portlet 還可能同時(shí)多次訪問同一個(gè)后端系統(tǒng)。Portlet 可能會(huì)在多個(gè)獨(dú)立的服務(wù)器線程中執(zhí)行其代碼以響應(yīng)不同的用戶請(qǐng)求。因此,有必要對(duì)訪問模式進(jìn)行了解,Portlet 或其他客戶機(jī)獲取事務(wù)或鎖定的方式可能會(huì)影響此類后端系統(tǒng)的平均響應(yīng)時(shí)間。
如果某個(gè) Portlet 在操作或呈現(xiàn)階段需要進(jìn)行密集的后端系統(tǒng)訪問,響應(yīng)時(shí)間(完成這些階段的時(shí)間)將越來越依賴于后端系統(tǒng)的響應(yīng)。(如果等待門戶服務(wù)器外的響應(yīng)以滿足傳入請(qǐng)求,將會(huì)帶來延遲,此延遲不能通過優(yōu)化 Portlet 代碼的執(zhí)行路徑得到改善。)具有后端系統(tǒng)通信的良好設(shè)計(jì),并了解事務(wù)行為通常可以得到更高的性能。
為了避免由于后端系統(tǒng)崩潰而使 Portlet(以及其所在頁面)停止響應(yīng),可以在代碼中加入超時(shí)機(jī)制;不過,請(qǐng)注意,管理和跟蹤時(shí)間戳?xí)硪恍┨幚黹_銷。如果使用了 WebSphere Portal 中的并行 Porlet 呈現(xiàn)功能(稍后討論),則可為并行呈現(xiàn)線程配置超時(shí)。
盡可能減少與此類外部后端系統(tǒng)的交互和數(shù)據(jù)通信流量也是不錯(cuò)的做法。為了實(shí)現(xiàn)這一點(diǎn),如果信息的刷新標(biāo)準(zhǔn)允許進(jìn)行緩存,Portlet 可以對(duì)信息進(jìn)行緩存。這可以減少為每個(gè)傳入 WebSphere Portal 請(qǐng)求多次獲取相同數(shù)據(jù)的往返次數(shù)。這樣還可以幫助降低后端系統(tǒng)上的負(fù)載,因?yàn)檫@樣就無需多次提供相同的信息了。另外,如果不需要在網(wǎng)絡(luò)上傳輸數(shù)據(jù),Portlet 可能可以更快地進(jìn)行呈現(xiàn)。
避免到后端系統(tǒng)的往返的另一個(gè)方法就是除了檢索滿足當(dāng)前請(qǐng)求實(shí)際所需的數(shù)據(jù)外,還檢索所知的將在可能的后續(xù)請(qǐng)求中所需的數(shù)據(jù)。不過,使用此方法時(shí),如果知道在后續(xù)請(qǐng)求中將要實(shí)際需要哪些預(yù)提取數(shù)據(jù),我們?nèi)匀唤ㄗh使用普通的預(yù)提取功能。為了合理地設(shè)計(jì)此特性,需要對(duì) Porlet 應(yīng)用程序的典型用戶交互非常了解。要記住,提前檢索會(huì)對(duì)門戶 JVM 的內(nèi)存使用造成影響。(請(qǐng)參閱性能和可伸縮性代碼設(shè)計(jì)。)此類設(shè)計(jì)方法可能需要更改后端系統(tǒng)的接口,但可以節(jié)約大量的處理時(shí)間,使得更改物超所值。
對(duì)于緩存,WebSphere Application Server 利用其面向的 Portlet 的 DistributedMap 接口提供了動(dòng)態(tài)緩存功能。(請(qǐng)參閱 WebSphere Application Server 5.1 信息中心以獲得更多的信息。)
會(huì)話與其他數(shù)據(jù)存儲(chǔ)區(qū)
保持和維護(hù) Portlet 的數(shù)據(jù),使其生存期長(zhǎng)于單個(gè)請(qǐng)求的生存期,這是一個(gè)典型的 Portlet 編程任務(wù)。通常考慮采用的第一個(gè)方法就是使用 PortletSession。從程序員的角度而言,PortletSession 使用很方便,但從應(yīng)用程序服務(wù)器的角度而言,管理會(huì)話需要使用資源。如果會(huì)話包含越來越多的數(shù)據(jù),從而要求使用更多的內(nèi)存,則會(huì)進(jìn)一步使問題嚴(yán)重化。
如果將會(huì)話配置為持久地存儲(chǔ)在數(shù)據(jù)庫中,或配置為進(jìn)行內(nèi)存到內(nèi)存復(fù)制(即在集群化環(huán)境中為 WebSphere Portal 配置了故障轉(zhuǎn)移),則該會(huì)話將在其內(nèi)容更改時(shí)被序列化。
當(dāng)會(huì)話數(shù)據(jù)寫入到遠(yuǎn)程副本時(shí),對(duì)會(huì)話數(shù)據(jù)進(jìn)行序列化和反序列化所需的時(shí)間可能變得非常大。在非常少見的情況下,存儲(chǔ)在會(huì)話中的某些對(duì)象可能被標(biāo)記為瞬態(tài)的。這將降低會(huì)話的序列化后的大小,但不會(huì)更改內(nèi)存的大小,而這對(duì)應(yīng)用程序服務(wù)器處理會(huì)話的效率也有影響。
大型的會(huì)話對(duì)象會(huì)減少可用以創(chuàng)建和執(zhí)行應(yīng)用程序?qū)ο蟮?JVM 內(nèi)存。因此,隨著可用堆內(nèi)存的減少而導(dǎo)致更頻繁的垃圾回收,性能可能會(huì)降低。
另一個(gè)因素就是內(nèi)存內(nèi)的生存期比所需的使用時(shí)間長(zhǎng),因此占用 Java 堆中的空間的會(huì)話數(shù)量通常比活動(dòng)用戶的數(shù)量多。在 WebSphere Application Server 中可以配置會(huì)話過期時(shí)間,這個(gè)屬性非常必要,可以防止在幾秒鐘沒有活動(dòng)后就要求用戶再次登錄的情況。會(huì)話的釋放由 WebSphere Application Server 和 Portlet 容器負(fù)責(zé)。
序列化的會(huì)話大小應(yīng)該小于 4KB,因?yàn)?WebSphere Application Server 能以可以接受的數(shù)據(jù)庫性能開銷存儲(chǔ)此類會(huì)話,在網(wǎng)絡(luò)上傳輸此類會(huì)話的時(shí)間也更少。如果會(huì)話大小超過了 32KB,數(shù)據(jù)庫必須使用面向二進(jìn)制大對(duì)象配置的表單元格,而如果此類會(huì)話從數(shù)據(jù)庫檢索或?qū)懭氲綌?shù)據(jù)庫中,則將需要訪問物理磁盤(對(duì)于大多數(shù)受支持的數(shù)據(jù)庫)。
由以上分析得出的第一個(gè)結(jié)論就是,從應(yīng)用程序的角度而言,應(yīng)該盡可能避免創(chuàng)建會(huì)話。在大多數(shù)公共頁面和無需身份驗(yàn)證的頁面上,通常不需要會(huì)話。在此類頁面上可以通過呈現(xiàn)鏈接與門戶進(jìn)行交互,而呈現(xiàn)鏈接定義為不更改服務(wù)器端的狀態(tài)。門戶將為每個(gè) Portlet 維護(hù)呈現(xiàn)參數(shù),以用于對(duì)該頁面的所有后續(xù)請(qǐng)求。為了避免 JSP 缺省創(chuàng)建會(huì)話,應(yīng)該將 JSP 中的頁面會(huì)話指令設(shè)置為 false:
|
否則,如果不存在會(huì)話,此 JSP 將創(chuàng)建一個(gè)會(huì)話。
以下的 Java 代碼片段演示了如何確保傳入會(huì)話加入現(xiàn)有的會(huì)話,而不是無條件地創(chuàng)建新會(huì)話:
|
將此參數(shù)的值設(shè)置為 false 時(shí),如果之前不存在會(huì)話,將不會(huì)創(chuàng)建會(huì)話。如果之前不存在會(huì)話,僅為了在其中存儲(chǔ)數(shù)據(jù)而在 Portlet 中創(chuàng)建一個(gè)會(huì)話,可能并不合適。
由以上分析得到的第二個(gè)結(jié)論就是,不要將會(huì)話誤用作通用數(shù)據(jù)存儲(chǔ)機(jī)制。請(qǐng)記住,我們的目的是盡可能使會(huì)話保持最小。如果由于 Portlet 的設(shè)計(jì),將某些數(shù)據(jù)保存在內(nèi)存中具有一定優(yōu)勢(shì),則可以使用緩存。可以使用會(huì)話 ID 設(shè)置緩存條目的范圍,以使會(huì)話和要保存在內(nèi)存中的數(shù)據(jù)建立關(guān)聯(lián)。請(qǐng)注意,此類緩存在呈現(xiàn)故障轉(zhuǎn)移時(shí)不支持集群;而這有時(shí)是可以接受的折衷。如果數(shù)據(jù)可以使用其他 Portlet 可用數(shù)據(jù)重新創(chuàng)建,則緩存條目的會(huì)話范圍要求就有待商榷。
在很多情況下,通過僅在會(huì)話中存儲(chǔ)一個(gè)鍵,并使用該鍵作為引用以在其他數(shù)據(jù)結(jié)構(gòu)中查找更大的對(duì)象,從而可以避免在會(huì)話中存儲(chǔ)大對(duì)象。另外,可以選擇使用相同信息的更緊湊的表示形式,而后將該對(duì)象放入會(huì)話中。
而且,Portlet 設(shè)計(jì)需要仔細(xì)考慮會(huì)話中實(shí)際存儲(chǔ)的內(nèi)容。會(huì)話通常僅旨在用于存儲(chǔ)用戶交互與門戶應(yīng)用程序的對(duì)話狀態(tài)(例如,網(wǎng)上商店 Porltet 中的購物車的內(nèi)容)。此類數(shù)據(jù)不能采用其他任何手段重新創(chuàng)建。在 WebSphere Portal 中,這種類型的數(shù)據(jù)處理稱為會(huì)話狀態(tài)。
如果并不需要會(huì)話狀態(tài),Portlet 可以使用其他數(shù)據(jù)存儲(chǔ)選項(xiàng):
-
在 Portlet 的操作階段,可以為 Portlet 的后續(xù)呈現(xiàn)階段設(shè)置呈現(xiàn)參數(shù)。Portlet 使用呈現(xiàn)參數(shù)呈現(xiàn)其特定于一組特定值的視圖。由容器在請(qǐng)求間維護(hù)呈現(xiàn)參數(shù),即使出現(xiàn)與其他 Portlet 的交互也是如此。在 WebSphere Portal 中,這種類型的數(shù)據(jù)處理稱為導(dǎo)航狀態(tài)。
-
如果需要跨多個(gè)用戶會(huì)話保持?jǐn)?shù)據(jù),則可以使用 PortletPreferences API 為 Portlet 存儲(chǔ)數(shù)據(jù)。請(qǐng)記住,此 API 并不能替代通用數(shù)據(jù)庫。在 WebSphere Portal 中,這種類型的數(shù)據(jù)處理稱為持久性狀態(tài)。
-
PortletConfig API 使 Portlet 可以讀取其配置,該配置由開發(fā)人員通過使用 Portlet 部署描述符提供;這對(duì)于 Porltet 的所有用戶均有效。
-
PortletContext API 允許存儲(chǔ)同一應(yīng)用程序中其他 Portlet 也可以訪問的屬性。
請(qǐng)考慮使用會(huì)話之外的其他選擇,將其用于存儲(chǔ) Portlet 創(chuàng)建和使用的數(shù)據(jù)。避免將可以通過用戶交互之外的其他源重新創(chuàng)建的數(shù)據(jù)復(fù)制到會(huì)話中。
與對(duì)特定的 Portlet 視圖尋址相比,使用呈現(xiàn)參數(shù)有很多優(yōu)勢(shì)。
如果 WebSphere Portal 檢測(cè)到了 Portlet 的操作參數(shù),則必須調(diào)用特殊的操作階段處理,使其具有不必使用操作參數(shù)的優(yōu)勢(shì)。不過,請(qǐng)注意,處理呈現(xiàn)鏈接時(shí)一定不能更改 Portlet 的服務(wù)器端狀態(tài)。要更改服務(wù)器端狀態(tài),唯一得到認(rèn)可的方法就是使用操作鏈接,而對(duì)于事務(wù)類型的請(qǐng)求,操作鏈接是最好的選擇。
使用呈現(xiàn)鏈接而不使用操作鏈接的例子很多。例如,假設(shè)一個(gè)報(bào)紙 Portlet 可以同使用“上一頁”和“下一頁”按鈕顯示特定的頁面。逐頁瀏覽報(bào)紙的頁面不一定會(huì)更改服務(wù)器端的狀態(tài),此狀態(tài)在本例中就是報(bào)紙中包含的全部信息。為了尋址報(bào)紙的下一頁,將下一頁的的頁碼編碼到所顯示按鈕的呈現(xiàn)鏈接中就足夠了。Portlet 可以根據(jù)呈現(xiàn)參數(shù)中所給的頁碼確定要呈現(xiàn)的頁面。
此外,由于每個(gè)呈現(xiàn)的視圖都由獨(dú)立的 URL 尋址,所以,通過使用呈現(xiàn)鏈接而不使用操作鏈接,還可以充分利用緩存基礎(chǔ)結(jié)構(gòu)(無論是瀏覽器緩存還是代理緩存)。URL 是用于訪問此類緩存基礎(chǔ)結(jié)構(gòu)中的特定生成視圖的唯一的鍵。
接下來的幾個(gè)部分中將討論開發(fā)人員應(yīng)該考慮的 WebSphere Portal 中可用的一些 Porlet 優(yōu)化功能,這些功能可以影響所選擇的實(shí)現(xiàn)技術(shù)。需要使用 Portlet 的部署描述符提供一些必須的設(shè)置,而且,由于這些項(xiàng)也是由 Portlet 開發(fā)人員提供的,因此被認(rèn)為是自定義代碼。
允許 Portlet 進(jìn)行并行呈現(xiàn)
WebSphere Portal 提供了讓頁面上的 Portlet 并行呈現(xiàn)的選項(xiàng)。此功能并非完全“免費(fèi)”的,因?yàn)樾枰?jì)算資源以維護(hù)和管理呈現(xiàn)每個(gè) Portlet 所使用的不同線程。
如果涉及到很多后端系統(tǒng),而每個(gè)后端系統(tǒng)在呈現(xiàn)單個(gè)頁面時(shí)都會(huì)產(chǎn)生延遲,此時(shí)使用并行 Portlet 呈現(xiàn)就具有一定優(yōu)勢(shì)。例如,假設(shè)一個(gè)門戶頁面包含很多 Portlet,每個(gè) Portlet 都會(huì)訪問不同的后端系統(tǒng)。在串行呈現(xiàn)模式中,從所有后端系統(tǒng)檢索所需數(shù)據(jù)的總體延遲為各個(gè)延遲時(shí)間的總和。而在并行呈現(xiàn)模式中,延遲時(shí)間應(yīng)為所有單個(gè)延遲時(shí)間中的最大值。
如果 Portlet 并不經(jīng)常使用后端系統(tǒng),由于啟用并行 Portlet 呈現(xiàn)所帶來的開銷可能會(huì)比由此功能所帶來的好處更大。如果頁面上的 Portlet 能夠獨(dú)立于后端系統(tǒng)進(jìn)行呈現(xiàn),則只需要門戶服務(wù)器計(jì)算機(jī)本地的 CPU 資源。這種情況下,頁面呈現(xiàn)響應(yīng)時(shí)間不會(huì)得到改進(jìn)。
可以使用圖形用戶界面、部署描述符或 WebSphere Portal 的 XML 訪問接口啟用并行 Portlet 呈現(xiàn)。而且,還有一個(gè)相關(guān)的全局屬性值,可以全面開啟和關(guān)閉并行 Portlet 呈現(xiàn)功能。
要正確回答是否支持并行 Portlet 呈現(xiàn)門戶這一問題,需要考慮若干事項(xiàng);例如,呈現(xiàn)頁面所涉及到的后端系統(tǒng)的數(shù)量、使用并行 Portlet 呈現(xiàn)的頁面上的 Portlet 的平均數(shù)量,等等。Portlet 開發(fā)人員事先不一定能給出這些問題答案,但如果合理的話,開發(fā)人員當(dāng)然事先可以確保為 Portlet 啟用了并行 Portlet 呈現(xiàn)。
在 Portlet 容器中進(jìn)行緩存
基于 Portlet 的 Web 頁面是動(dòng)態(tài)聚合的,因?yàn)樗鼈兡芤詡€(gè)性化的方式提供動(dòng)態(tài)內(nèi)容。這個(gè)靈活性具有一定的開銷。由于為了響應(yīng)請(qǐng)求生成這些頁面必須進(jìn)行額外的工作,故而網(wǎng)站的響應(yīng)時(shí)間將增加。
新的緩存技術(shù)將改善動(dòng)態(tài)頁面的生成和減少系統(tǒng)負(fù)載。WebSphere Portal 支持片斷緩存(也稱為 Servlet 緩存),可以使用 WebSphere Application Server 動(dòng)態(tài)緩存在緩存中保存 Portlet 輸出。對(duì)緩存的 Portlet 的請(qǐng)求將從緩存(而不是 Portlet)檢索內(nèi)容。可以通過在部署描述符中指定過期實(shí)現(xiàn)片斷緩存的失效。而且,在 Portlet 的操作階段也會(huì)使片斷緩存條目失效。
激活片斷緩存不需要進(jìn)行費(fèi)時(shí)的安裝和集成工作。通過使用簡(jiǎn)單的 XML 部署描述符文件和通過使用 WebSphere Application Server 管理控制臺(tái)均可以啟用和禁用該緩存功能。(請(qǐng)參閱 WebSphere Portal 信息中心,以了解在 WebSphere Application Server 中啟用 Servlet 緩存的詳細(xì)信息。)
為了使用基于過期的緩存,Portlet 必須在部署描述符 portlet.xml(對(duì)于符合 JSR 168 規(guī)范的標(biāo)準(zhǔn)化 Portlet)中定義過期緩存的持續(xù)時(shí)間:
|
-
整數(shù)定義緩存條目在緩存中存在的秒數(shù)值。
-
值 -1 指示 Portlet 緩存永遠(yuǎn)不過期。
-
值 0 指示為該 Portlet 禁用緩存功能。
一定不能在同一 Portlet 的所有用戶間共享緩存的條目。此緩存技術(shù)是基于特定 Portlet 的特定用戶的。
對(duì)于在其部署描述符中定義了過期緩存的 JSR 168 Portlet,Portlet 窗口可以在運(yùn)行時(shí)通過設(shè)置 RenderResponse 中的 EXPIRATION_CACHE 屬性修改過期時(shí)間,如下所示:
|
對(duì)于在從后端(如 EJB 組件和數(shù)據(jù)庫)計(jì)算其響應(yīng)和請(qǐng)求數(shù)據(jù)時(shí)計(jì)算時(shí)間很長(zhǎng)的復(fù)雜 Portlet,此方法非常有用。對(duì)于簡(jiǎn)單 Portlet,不應(yīng)啟用片斷緩存。WebSphere Portal 將使用額外的執(zhí)行資源計(jì)算機(jī)片斷緩存的內(nèi)部緩存鍵。對(duì)于簡(jiǎn)單 Portlet,由于緩存鍵計(jì)算比重新計(jì)算 Portlet 響應(yīng)開銷更大,其性能可能會(huì)降低。
對(duì)于真正動(dòng)態(tài)的 Portlet,片斷緩存并不適用;如,對(duì)每個(gè)請(qǐng)求都需要從其他數(shù)據(jù)源收集當(dāng)前數(shù)據(jù)的基于實(shí)時(shí)的 Portlet 或?qū)γ總€(gè)請(qǐng)求都會(huì)更改其響應(yīng)標(biāo)記的 Portlet。這將會(huì)導(dǎo)致大量的緩存失效,因此性能不會(huì)得到提高。所以,僅在 Portlet 的輸出在更新前會(huì)在一段時(shí)間內(nèi)保持有效的情況下才應(yīng)該為 Portlet 啟用緩存功能。
在遠(yuǎn)程緩存中進(jìn)行緩存
通過獨(dú)特的自適應(yīng)緩存功能,WebSphere Portal 可以在門戶緩存之外的緩存(稱為遠(yuǎn)程緩存)中動(dòng)態(tài)緩存生成的頁面(如果所有頁面組件均指示自身可以緩存)。如果從遠(yuǎn)程提供完全呈現(xiàn)的頁面,就可以避免到門戶服務(wù)器的往返,此類頁面的響應(yīng)時(shí)間可以與從靜態(tài)網(wǎng)站提供時(shí)一樣快。
有關(guān)遠(yuǎn)程緩存的全部詳細(xì)信息,請(qǐng)參閱使用 WebSphere Portal V5.1 開發(fā)包含靜態(tài)內(nèi)容和動(dòng)態(tài)內(nèi)容的高性能網(wǎng)站。
Portlet(以及主題)可以提供完全呈現(xiàn)頁面的總體遠(yuǎn)程緩存信息中其所特定的遠(yuǎn)程緩存信息。遠(yuǎn)程緩存信息一個(gè)數(shù)據(jù)結(jié)構(gòu),由關(guān)于緩存范圍(是否可緩存,是共享的,還是非共享的)和過期時(shí)間(內(nèi)容在多長(zhǎng)時(shí)間內(nèi)為有效)的信息組成。可以通過部署描述符或 WebSphere Portal GUI 提供 Portlet 的遠(yuǎn)程緩存信息。除此之外,Portlet 還可以在呈現(xiàn)時(shí)為每個(gè) Portlet 提供遠(yuǎn)程緩存信息,如下面的代碼中所示:
|
設(shè)置遠(yuǎn)程緩存信息的方式依賴于呈現(xiàn)的視圖的“刷新”要求和范圍。請(qǐng)注意,如果從緩存提供呈現(xiàn)的頁面,請(qǐng)求可能甚至不會(huì)發(fā)送到門戶服務(wù)器。
如果可以在基礎(chǔ)結(jié)構(gòu)中使用緩存,自定義 Portlet 開發(fā)人員應(yīng)當(dāng)考慮利用遠(yuǎn)程緩存功能。
在門戶術(shù)語中,主題是確定門戶應(yīng)用程序的外觀和風(fēng)格的若干 JSP 集。由于主題由 JSP 組成,在 JSP 部分給出的技巧也適用于此。這一部分詳細(xì)討論了使用組成主題的 JSP 文件集可能存在的性能缺陷。
通常,主題由很多不同的文件組成,每個(gè)文件提供屏幕的特定區(qū)域的內(nèi)容。盡管可以動(dòng)態(tài)地包含 JSP,但通常(也建議)將 JSP 靜態(tài)包含在其他 JSP 中。
由于編譯時(shí)可能會(huì)將很多 JSP 包含到其他 JSP 中,所得的 Java 源代碼和 Servlet 字節(jié)代碼文件可能會(huì)非常大。使用大的類文件通常不會(huì)有性能問題,但由于 Java 編程語言中包含的大小限制,可能不能將 Java 源代碼編譯為類。例如,Java 中的方法的大小不能超過 64KB。大型的復(fù)雜主題很容易達(dá)到這個(gè)限制,而導(dǎo)致不再能編譯。這種情況下,有三種選擇:
-
用動(dòng)態(tài)包含代替一些(而非全部)靜態(tài)包含。
如 JSP 部分 (LINK) 提到的,這是用性能作為交換,以便能編譯 JSP。從性能的角度而言,盡管這個(gè)方法最易于實(shí)現(xiàn),但卻是最不好的解決方法。
-
盡量限制 JSP 中 Scriptlet 的使用。
WebSphere Application Server 可以對(duì)僅調(diào)用標(biāo)記處理程序的代碼進(jìn)行優(yōu)化,而這可以有助于使文件保持在 64KB 的上限之內(nèi)。
-
清除 JSP 代碼。
這些文件通常包含并非必要的多余代碼。通常刪除 HTML 注釋行或空白,或者將 JavaScript 代碼移動(dòng)到單獨(dú)的文件中均可保證足夠的空間。
主題有時(shí)會(huì)完成應(yīng)用程序中復(fù)雜的任務(wù)。不過此時(shí)應(yīng)該謹(jǐn)慎。請(qǐng)記住,對(duì)于門戶的每個(gè)請(qǐng)求,都會(huì)呈現(xiàn)主題,因此不要在其中進(jìn)行會(huì)給系統(tǒng)帶來高負(fù)荷的計(jì)算工作。
在模擬門戶功能時(shí)要特別謹(jǐn)慎。例如,主題可能會(huì)循環(huán)訪問門戶應(yīng)用程序中的大量頁面;應(yīng)該對(duì)此進(jìn)行篩選,僅向用戶顯示一個(gè)導(dǎo)航結(jié)構(gòu),其中僅包含主題從門戶 API 請(qǐng)求的若干頁面。這種情況下,門戶中進(jìn)行的很多處理都會(huì)丟失,因?yàn)橹髸?huì)將其結(jié)果丟棄。此處根據(jù)門戶訪問控制或個(gè)性化規(guī)則進(jìn)行篩選會(huì)更為有效。
此外,要盡量限制門戶頁面中門戶資源鏈接的數(shù)量。門戶必須生成的每個(gè) URL 鏈接都會(huì)給系統(tǒng)帶來額外的負(fù)載。如果需要具有大量鏈接的應(yīng)用程序主題,請(qǐng)嘗試緩存其中的一些頁面,從而使其不必在每次請(qǐng)求時(shí)都重新計(jì)算所有鏈接。
主題也是 WebSphere Portal 中的遠(yuǎn)程緩存基礎(chǔ)結(jié)構(gòu)的一部分。主題的遠(yuǎn)程緩存是一組可以通過 XML 訪問具體指定的元數(shù)據(jù),如以下示例中所示:
|
主題不能提供任何呈現(xiàn)時(shí)遠(yuǎn)程緩存信息。
WebSphere Portal 支持高性能外觀的識(shí)別。這些外觀非常特殊,因?yàn)樗鼈儾皇腔?JSP 生成的;它們的輸出是根據(jù)預(yù)編譯的 Java 類創(chuàng)建的。當(dāng)然,此類外觀的可自定義性要差一些;只能對(duì)樣式表信息和包含的圖像進(jìn)行修改。不過,如果性能是您要考慮的最重要的因素的話,就應(yīng)該考慮為頁面上特定的元素或特定 Portlet 啟用高性能外觀。(請(qǐng)參閱參考資料中的信息中心以了解詳細(xì)信息,包括各種可幫助您編寫高速外觀和主題的提示。)
在 WebSphere Portal 應(yīng)用程序開發(fā)和驗(yàn)證的所有階段均可以使用各種工具提供幫助。本部分對(duì)不同開發(fā)周期中可以使用的不同工具類別進(jìn)行了說明,并提供了一些例子,以幫助您進(jìn)行自定義代碼的開發(fā)和分析。
從技術(shù)角度而言,可以使用任何文本編輯器編寫 Portlet、主題和外觀,但使用集成開發(fā)環(huán)境(如將 IBM Rational? Application Developer 和 IBM Portal Toolkit 結(jié)合使用)要方便很多。還可以使用 Portlet 代碼示例和基本門戶代碼片斷開速入門;該開發(fā)環(huán)境還與一個(gè)門戶服務(wù)器進(jìn)行了集成,以便立即部署和測(cè)試代碼。
當(dāng)代碼就緒,可以部署時(shí),需要詳細(xì)了解其可能的性能問題。可以采取若干步驟(下面對(duì)此進(jìn)行了總結(jié)),但性能方面有一條始終適用的一般規(guī)則:在大多數(shù)程序中,約有 80% 的執(zhí)行時(shí)間都花在 20% 的應(yīng)用程序代碼中。這 20% 的代碼位于“關(guān)鍵路徑”上,正是這些方面值得進(jìn)行性能優(yōu)化。例如,Portlet 的呈現(xiàn)方法要比其初始方法的性能關(guān)鍵性更強(qiáng),因?yàn)槊總€(gè)請(qǐng)求都會(huì)調(diào)用呈現(xiàn)方法。
-
代碼分析應(yīng)在開發(fā)的早期階段進(jìn)行,或?qū)⑵渥鳛殚_發(fā)后的第一個(gè)性能測(cè)試。分析意味著將在方法級(jí)收集執(zhí)行時(shí)信息,通常會(huì)使用 JVMPI 接口進(jìn)行此項(xiàng)工作。分析器結(jié)果可以幫助標(biāo)識(shí)應(yīng)用程序的關(guān)鍵路徑;即大部分時(shí)間所執(zhí)行的代碼。分析器還通常會(huì)給出關(guān)于對(duì)象創(chuàng)建速率和內(nèi)存使用的信息。
-
IBM Rational Application Developer 提供了一個(gè)分析代理,可以使用該代理測(cè)試程序。
-
Eclipse Test and Performance Tools Platform 是一個(gè) Eclipse 項(xiàng)目,提供了基于 Eclipse 的開放源代碼分析功能支持。
-
-
一旦將 Portlet 部署到了門戶中,就應(yīng)該測(cè)試 Portlet 在負(fù)載下的行為。壓力或負(fù)載生成器(如 Rational Performance Tester、Rational Robot、Apache JMeter 等等)是具有成本效益的負(fù)載測(cè)試解決方案,可以幫助您準(zhǔn)確地模擬生產(chǎn)負(fù)載下的系統(tǒng)性能。這些工具將收集大量信息,以幫助確定系統(tǒng)是否具有良好的性能設(shè)計(jì),其中包括關(guān)于請(qǐng)求響應(yīng)時(shí)間、處理器使用率等的數(shù)據(jù)。
-
在負(fù)載測(cè)試期間,應(yīng)該監(jiān)視門戶環(huán)境中的若干性能參數(shù)。IBM Tivoli? Performance Viewer(與 WebSphere Application Server 一起提供)可以幫助監(jiān)視應(yīng)用程序服務(wù)器內(nèi)的資源使用情況。
-
門戶環(huán)境的許多問題都和內(nèi)存有關(guān)。JVM 實(shí)現(xiàn)為工具提供了兩類信息,以供進(jìn)行性能分析:
- 垃圾回收器的輸出 verbose:gc。
- 堆轉(zhuǎn)儲(chǔ),發(fā)現(xiàn)內(nèi)存泄漏時(shí)非常有用。
在 IBM alphaWorks 中可以得到垃圾回收器輸出的分析工具。而另一方面,heapRoots 則是一款強(qiáng)大的堆轉(zhuǎn)儲(chǔ)分析輔助工具。《IBM Java 診斷指南》也提供了處理門戶的相關(guān)性能問題的有用信息。請(qǐng)參閱參考資料,以獲得這些參考資料的鏈接。
開發(fā) WebSphere Portal 代碼時(shí),通常不需要所有這些工具,但要在生產(chǎn)環(huán)境中推出更大的門戶,必須從性能的角度對(duì)門戶代碼有個(gè)良好的理解。
創(chuàng)建自定義門戶代碼時(shí),開發(fā)人員必須考慮很多方面的因素,以確保門戶性能得到優(yōu)化。小結(jié)如下:
-
將精力主要放在關(guān)鍵代碼路徑的改進(jìn)上。關(guān)鍵代碼路徑是處理時(shí)間長(zhǎng)或頻繁執(zhí)行的代碼路徑。找到哪些類的哪些方法位于關(guān)鍵路徑上。在關(guān)鍵路徑外的優(yōu)化效果相當(dāng)小。
-
要同時(shí)兼顧執(zhí)行性能和內(nèi)存分配。
-
使用恰當(dāng)?shù)墓ぞ邷y(cè)量和分析代碼,以獲得最典型的用戶交互。
-
不同編碼問題解決方案可能有很大的性能變化。
-
必須全面了解處理發(fā)現(xiàn)的性能問題的特定實(shí)現(xiàn)的細(xì)節(jié)。
-
設(shè)計(jì)自定義代碼時(shí)要考慮后端訪問模式。
-
不要錯(cuò)誤地將會(huì)話作為 Portlet 的通用數(shù)據(jù)存儲(chǔ)區(qū)使用。可以采用更好地方法處理數(shù)據(jù),以滿足各種不同的實(shí)現(xiàn)要求。
-
考慮利用 WebSphere Application Server 和 WebSphere Portal 提供的特殊功能以優(yōu)化 Portlet 性能(假設(shè)目標(biāo)環(huán)境也在使用相同的功能)。
posted @ 2006-04-04 12:44 劉軍偉 閱讀(669) | 評(píng)論 (0) | 編輯 收藏