Servlet和JSP的協調運行——通過調整Servlet和JSP來提高你的公司專屬應用程式的運行效能
最後更新:2018-12-03
來源:互聯網
上載者:User
Servlet和JSP的協調運行
——通過調整Servlet和JSP來提高你的企業應該的運行效能
作者:Rahul Chaudhary
簡介
在這篇文章裡,Rahul Chaudhary描述了能夠提高Servlet和JSP效能的效能協調技術(performance-tuning techniques,簡稱PTT技術),因而使用它來提高你的J2EE應用的效能。作者認為這篇文章的讀者都應該具有Servlet和JSP的基礎知識。
你的J2EE應用運行很慢嗎?
它們能夠支撐不斷上升的訪問量嗎?
這篇文章描述了為開發高效能和大規模的Servlet和JSP應用而提出的performance- tuning技術(PTT)。這種技術使得我們能夠開發這樣的應用:它的運行速度相當的快,並且能夠從始至終保持這種快速,更為重要的是能大幅度的提高應用的使用者數或者請求數。在這篇文章裡,我將帶領你實踐和證明performance-tuning技術能夠大幅度推進你的Servlet和JSP的效能,從而達到提高你的J2EE應用的目的。這些技術有一些是在開發環節使用的,如設計或編碼階段;還有一些是和配置相關的。
PTT1:使用HttpServlet的init()方法來快取資料 Web伺服器調用init()方法是在伺服器建立Servlet執行個體之後,而在Servlet處理所有請求之前。在一個Servlet的生命週期裡,它只被調用一次。Init()方法能用來提高效能,通過緩衝待用資料,或完成那些在初始化階段需要被執行的開銷昂貴的動作。
例如,使用JDBC(Java Database Connectivity)串連池是一個被實踐證明很好的方法,這些串連池通常包括一個javax.sql.DataSource介面。DataSource是通過JDNI(Java Naming and Directory Interface)樹獲得。對每一個SQL的調用,運行JDNI來擷取DataSource對系統的效能來說是一個昂貴的、能產生重大的影響。Servlet的init()方法能夠被用來擷取DataSource,並且緩衝起來留給後面使用。
public class ControllerServlet extends HttpServlet{ private javax.sql.DataSource testDS = null; public void init(ServletConfig config) throws ServletException { super.init(config); Context ctx = null; try { ctx = new InitialContext(); testDS = (javax.sql.DataSource)ctx.lookup("jdbc/testDS"); } catch(NamingException ne) {
ne.printStackTrace();
} catch(Exception e) { e.printStackTrace(); }
} public javax.sql.DataSource getTestDS() { return testDS; } }
PTT2:關掉Servlet和JSP的auto-reloading
Servlet/JSP的auto-reloading屬性在開發階段被證明是非常有用的,因為它減少了開發時間,你在每一次更改Servlet或JSP的時候不用重新啟動伺服器。然而,它在實用階段又是極其昂貴的,由於必要的裝載或擔負ClassLoader,Servlet/JSP的auto-reloading有極低效率。還有,當某些類的特定的ClassLoader不能和當前的類使用的ClassLoader協調工作時,你的應用系統就會發生奇怪的衝突。所以,在工作環境關掉Servlet/JSP的auto-reloading將獲得良好的效能。
PTT3:控制HttpSession 許多系統需要一序列的用戶端請求以便它們能夠和其他系統關聯。這時候,基於Web的應用需要維護一個狀態,這個狀態成為Session,因為HTTP協議是無狀態的。為了支援系統必須維護的這個狀態,Java Servlet提供了API來管理Sessions,允許通過幾種機制來實現Session。Sessions的一切作用由HttpSession對象來代表,但是使用它有昂貴的開銷。當一個HttpSession對象更新的時候,無論是它被使用的時候還是被複寫的時候,它都要被讀取。你可以通過使用下面的技術來提高效能: 。不要在JSP頁面的預設狀態下產生HttpSession:預設狀態下,JSP頁面產生HttpSession。如果你不在JSP頁面使用HttpSession,為了節省一些效能開銷,當它們在JSP頁面不是必須的時候,使用下面的命令來阻止自動產生HttpSession:
<%@ page session="false"%> 。不要在HttpSession裡儲存大的對象曲線或者圖表:如果儲存那樣的資料在HttpSession裡,應用伺服器不得不每次都要處理整個的HttpSession對象。這將迫使Java系列化並且增加了計算的花費。 。當HttpSession使用完的時候釋放HttpSession對象:使用HttpSession.invalidate()方法來釋放HttpSession,當不再需要它們時。 。設定Session的time-out值:Servlet引擎有一個預設的time-out值設定。如果你不刪掉HttpSession或者使用它的時間達到time-out設定的時間,Servlet引擎將會從記憶體中刪掉該對象。設定time-out的時間越大,對可測性和效能的影響越大,原因是由於記憶體和記憶體回收的開銷。盡量使得sessions的time-out時間盡量小。
PTT4:使用gzip壓縮 壓縮是一種去掉多餘的資訊,用最小的空間來儲存你所需要的資料的方法。對於HMTL檔案來說,使用gzip(GNU zip)壓縮文檔能夠極大的減少下載時間。你的資訊大小越小,它就能很快的被發送出去。因而,如果你壓縮你的Web應用產生的內容,那麼它將很快的傳到使用者那裡,並且能更快的顯示給使用者。不是所有的瀏覽器都支援gzip壓縮,但是你能很容易的檢測一個瀏覽器是否支援gzip,然後發送gzip壓縮的內容給那些支援gzip壓縮的瀏覽器。
下面是一個代碼片斷,用來示範如果瀏覽器可以接收的話,發送壓縮內容:
public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException { OutputStream out = null // Check the Accepting-Encoding header from the HTTP request. // If the header includes gzip, choose GZIP. // If the header includes compress, choose ZIP. // Otherwise choose no compression. String encoding = request.getHeader("Accept-Encoding"); if (encoding != null && encoding.indexOf("gzip") != -1) { response.setHeader("Content-Encoding" , "gzip"); out = new GZIPOutputStream(response.getOutputStream()); } else if (encoding != null && encoding.indexOf("compress") != -1) { response.setHeader("Content-Encoding" , "compress"); out = new ZIPOutputStream(response.getOutputStream()); } else { out = response.getOutputStream(); }}
PTT5:不要使用SingleThreadModel SingleThreadModel使得Servlet一次只能處理一個請求。如果一個Servlet實現了這個介面,Servlet引擎為每一個新的請求產生一個獨立的Servlet執行個體。這將導致系統對象數量上的開銷。如果你要解決安全執行緒方面的問題,使用其他的方法而不是實現SigleThreadModel介面。SigleThreadModel介面已經在Servlet2.4被廢棄了。
PTT6:使用線程池 Servlet引擎為每一個請求產生一個獨立的線程,將這些線程分配到service()方法裡,service()方法執行以後,刪掉這些線程。預設情況下,Servlet引擎將為每一個請求產生一個線程。這些預設的行為降低了系統的效能,因為產生和刪除線程的開銷是昂貴的。這些效能能夠通過使用線程池得到改善。通過預測並發訪問系統的使用者的數目,設定在池內和增加的最大、最小的數量來配置一個線程池。啟動的時候,Servlet引擎產生一個線程池,這個線程池擁有你所配置的最小的數目的線程。然後,Servlet引擎從池內分配線程到每一個請求,而不是為每一個請求產生一個線程。當線程使用完成以後,將線程返回到線程池。使用線程池,系統的效能能得到徹底的提高。如果需要,更多線程也可以線上程的最小數目的基礎上進行增加。
PTT7:選擇正確的include機制 在JSP頁面上,有兩種方法供我們引入一個檔案:include引用(<%@ include file="test.jsp" %>)和include動作(<jsp:include page="test.jsp" flush="true" />)。Include引用在轉化階段引入詳細的檔案內容,即,頁面轉化為Servlet。Include動作在處理請求的階段引入檔案內容,即,當使用者請求頁面的時候,include引用比include動作快。所以,除非引用的檔案經常改變,使用include引用能獲得一個好的效能。
PTT8:在使用usebean動作的時候,使用正確的範圍 使用JSP頁面的一個有力的武器是和Javabean組件結合起來使用。通過標籤<jsp:useBean>,Javabean能夠直接嵌入到JSP頁面,文法如下:
<jsp:useBean id="name" scope="page|request|session|application" class=package.className" type="typeName"></jsp:useBean>
scope屬性給出Javabean可見度的範圍,預設值是page。你可以根據你的應用的需要選擇一個適合的值。否則,它會影響你的系統的效能。
例如,你僅僅需要一個對象為一個特殊的請求,但是你的scope卻設定到session,那麼那個對象會一直存在,而你的請求已經結束很長時間了。它會停留在記憶體裡,直到你明確的刪掉它,或者使session無效,或者根據你在Servlet引擎裡設定的timeout值session已經timeout。如果你沒有正確選擇scope的值,它會影響效能因為記憶體和記憶體回收的開銷。所以我們要選擇正確的scope值,並且在對象使用完以後馬上把它們刪掉。
複合技術 。避免String的聯結。使用”+”運算子來連接字串將產生很多的臨時對象,因為String對象是一個常量。你對”+”使用的越多,臨時對象就產生得越多,這會大大降低系統的效能。使用StringBuffer而不是”+”當你需要串連很多的字串的時候。 。避免使用System.out.println:System.out.println同步處理磁碟的I/O系統,這醒目的降低了輸入輸出量。盡量得避免使用System.out.println,即使這個怪異的debug工具是可用的。有時候,由於跟蹤的目的,System.out.println還是有用的,或者列印錯誤,或者debuging。你應該配置System.out.println,使它僅僅在error和debuging的情況下有效。為了做到這一點,使用一個boolean變數,當這個boolean變數是false的時候,最佳化out使之在編譯階段的檢測和跟蹤的時候有效。 。ServletOutputStream對PrintWriter:使用後者將導致小的開銷,因為它意味著字元輸出資料流和將資料編碼為位元組碼。所以PrintWriter能保證所有的字元轉化能夠正確進行。另一方面,當你是用ServletOutputStream的時候,你的Servlet僅僅返回二進位碼,因而你能減少字元轉化的開銷因為Servlet容器不編碼二進位碼。
結論 這篇文章的目的是向你展示一些實用的,已經被證明了的效能協調技術,這些技術將極大的推進Servlet/JSP的效能,因而提高了整個系統的效能。下一步我們將深入的探討其他相關技術如EJB (Enterprise JavaBeans), JMS (Java Message Service),,and JDBC (Java Database Connectivity)的效能協調技術。