转自:http://my.oschina.net/xiandafu/blog/475740
JSP是预编译成class的,然后模板渲染里比Beetl慢很多,文章从JSP静态文本处理不足,以及JSTL实现低效来说明JSP实际上要比Beetl慢2倍,FreeMarker比Beetl慢6倍多。从客观的基准测试和第三方性能测试也能证明这一点。
许多人都不相信这个事实,作为前端常用渲染技术,JSP比Beetl慢。如果稍微了解这俩种技术的人,会分析:JSP是编译成class的,而 Beetl总是解释执行的。JSP肯定会比Beetl快。然而,事实并不是这样,通过了许多性能测试,证明,Beetl还是要快的,如下是TEB模板引擎 性能基准测试结果:
采用jfinal+beetl模板,apache ab压力测试结果
- Time taken for tests: 0.656 seconds
- Complete requests: 1000
- Time per request: 32.813 [ms] (mean)
未采用beetl,apache ab测试结果:
- Time taken for tests: 1.297 seconds
- Complete requests: 1000
- Time per request: 64.844 [ms] (mean)
究竟怎么回事情,使得编译执行的JSP执行比解释执行的Beetl慢。基本上来说,Beetl并没有做出超越常规的性能优化,而是JSP本身性能优化不够导致的。
<%@ page language="java" contentType="text/html; charset=UTF-8" 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>");
public static void 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)); } } public static void write(byte[] bs){ }
输出是:
jsp total=228
beetl total=3
<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));
也就是,JSP并没有如预期的预编译成java代码,而是动态解释执行了 test条件,这样,性能不差才怪呢.