為什麼JSP渲染比常用模板(freemarker\Velcoity\beetl)慢
阿新 • • 發佈:2019-01-04
提升渲染效能方法有:
模板引擎將模板檔案編譯成class執行。
模板中的靜態部分採用二進位制輸出,不需要CPU執行的時候再轉碼
合併模板中的靜態部分一起輸出,而不是每一行每一行輸出
第一: JSP對靜態文字處理的不夠好。
如果你看看JSP編譯的後的java程式碼(以Tocmat7為例),你會發現,JSP並沒有優化好靜態文字輸出。如下一個JSP程式碼
- <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
- pageEncoding="UTF-8"%>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Test JSP</title>
- </head>
- <body>
- <%
- String a = "Test JSP";
- %>
- <%=a %>
- </body>
- </html>
Tomcat7 會編譯成為
- out.write("<html>\r\n");
- out.write("<head>\r\n");
- out.write("<meta http-equiv=\"Content-Type\"
- content=\"text/html; charset=ISO-8859-1\">\r\n");
- out.write("<title>Test JSP</title>\r\n");
- out.write("</head>\r\n");
- out.write("<body>\r\n");
- String a = "Test JSP";
- out.write('\r');
- out.write('\n');
- out.print(a );
- out.write("\r\n");
- out.write("</body>\r\n");
- out.write("</html>"
可以看出,對於靜態文字,JSP會多次呼叫out.write方法,而write方法內部,每次呼叫,都會做flush檢測等耗時機制。因此,更好的方式應該是將靜態文字合併一次性輸出,應該是下面這種會更好點
// 期望JSP的樣子
- out.write("<html>\r\n<head>\r\n ....<body>\r\n“);
- String a = "Test JSP";
- out.write("\r\n“);
- out.print(a );
- out.write("\r\n</body>\r\n</html>");
第二 就算JSP的實現做了如上更改,靜態文字處理還有優化空間。這是因為網際網路傳輸的二進位制,因此會存在一個將靜態文字轉成 byte[] 輸出的過程,這是一個耗費CPU操作的過程,也就是JSP裡的write操作,內部還大量的編碼,而且,隨著JSP一次次渲染,編碼是一次一次重複,實驗 證明,這極大的降低了JSP效能。通過如下虛擬碼可以驗證
- publicstaticvoid main(String[] args)throws Exception {
- String text = "<html>你好中文!你好中文!你好中文!</html>";
- {
- //模擬jsp
- long start = System.currentTimeMillis();
- for(int i=0;i<1000000;i++){
- byte[] bs = text.getBytes("UTF-8");
- write(bs);
- }
- long end = System.currentTimeMillis();
- System.out.println("jsp total="+(end-start));
- }
- {
- // 模擬beetl
- long start = System.currentTimeMillis();
- byte[] bs = text.getBytes("UTF-8");
- for(int i=0;i<1000000;i++){
- write(bs);
- }
- long end = System.currentTimeMillis();
- System.out.println("beetl total="+(end-start));
- }
- }
- publicstaticvoid write(byte[] bs){
- }
輸出是:
-
jsp total=228
-
beetl total=3
可見Beetl將靜態文字預先編碼成二進位制,會提高效能很多。而通常JSP,總是靜態文字多過JSP Code的
第三,JSP在JSTL做的不夠完美,也導致效能很差。
由於JSP是基於Java語言,語言本身是OO的,很多地方不適合模板場景使用,因此,自然而然採用JSTL來彌補JSP的不足,這也是後來很多專案都基本上採用了JSTL來寫模板。然而,JSTL的效能更加有問題。比如下一個簡單的JSTL判斷
- <c:choose>
- <c:when test="${param.newFlag== '1' || param.newFlag== '2'}">
- <th>1 or 2 <font color="Red">*</font>
- </c:when>
- </c:choose>
在我最初的想象裡,我認為jsp至少會編譯成如下程式碼:
//期望JSP能編譯成如下程式碼
- if(request.getParameter("newFlag").equals("1")
- ||request.getParameter("newFlag").equals("2")){
- out.print(...)
- }
但事實並不是這樣,對於如上JSTL,編譯成
- // 實際上JSP編譯的程式碼
- out.write((java.lang.String)
- org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(
- "${param.newFlag== '1' || param.newFlag== '2'}",
- java.lang.String.class,
- (javax.servlet.jsp.PageContext)_jspx_page_context, null, false));