2010-07-28 46 views
3

这是一个后续的“JSP的开销包括”下面的问题:JSP:包括性能,模块化,备选方案和最佳实践,第96

JSP Performance using jsp:include

在我们的应用程序,开发者'jsp:includes'用于在整个应用程序中重复使用的“common”jsp代码,从而“模块化”jsp片段。

优点

亲的如下:

  • 它DRY--我们曾经定义JSP片段。当您需要更改某些html并且不需要查找/替换/搜索/销毁时,这是一个很大的帮助。

  • 它很容易遵循:你清楚地传递参数。当你编辑'收录'页面时,你'知道你正在收到',也就是'包含/调用'页面中声明的一些'全局变量'。额外的请求

缺点

  • 性能开销

问题

所以作为后续:

  • 'jsp:include'会产生多少性能开销?从tomcat代码中并不明显(尽管你看到它比内联调用要多得多)。另外在分析应用程序时我从来没有requestDispatcher.include()或invoke()方法显示为热点。
  • 有人可以指出在哪里正是谎言的大部分开销? (即类Y中的方法X)或者它是否只是每个请求发生的所有“小东西”(例如,设置属性或对象创建以及随后的GC)?
  • 有什么选择? (AFAIK @include和jsp:include。其他什么东西?)
  • (愚蠢的奖金问题)为什么在编译时servlet引擎'包含'jsp,即像'带参数的内联宏'一样,这样我们的开发人员可以得到'jsp:include'的清晰度和'@include'的性能。

我一直在想这最后一个问题。我在过去的生活中使用过代码生成工具,从来没有完全理解缺少包含jsp片段的选项。

为了读者的利益,我已经包含了tomcat的'applicationDispatcher.invoke()'方法(tomcat 5.5。抱歉,如果它的日期)。为了清楚起见,我修剪了异常处理。

在此先感谢

private void invoke(ServletRequest request, ServletResponse response, 
     State state) throws IOException, ServletException { 

    // Checking to see if the context classloader is the current context 
    // classloader. If it's not, we're saving it, and setting the context 
    // classloader to the Context classloader 
    ClassLoader oldCCL = Thread.currentThread().getContextClassLoader(); 
    ClassLoader contextClassLoader = context.getLoader().getClassLoader(); 

    if (oldCCL != contextClassLoader) { 
     Thread.currentThread().setContextClassLoader(contextClassLoader); 
    } else { 
     oldCCL = null; 
    } 

    // Initialize local variables we may need 
    HttpServletResponse hresponse = (HttpServletResponse) response; 
    Servlet servlet = null; 
    IOException ioException = null; 
    ServletException servletException = null; 
    RuntimeException runtimeException = null; 
    boolean unavailable = false; 

    // Check for the servlet being marked unavailable 
    if (wrapper.isUnavailable()) { 
     wrapper.getLogger().warn(
       sm.getString("applicationDispatcher.isUnavailable", 
       wrapper.getName())); 
     long available = wrapper.getAvailable(); 
     if ((available > 0L) && (available < Long.MAX_VALUE)) 
      hresponse.setDateHeader("Retry-After", available); 
     hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm 
       .getString("applicationDispatcher.isUnavailable", wrapper 
         .getName())); 
     unavailable = true; 
    } 

    // Allocate a servlet instance to process this request 
    try { 
     if (!unavailable) { 
      servlet = wrapper.allocate(); 
     } 
    } 
    ...exception handling here.... 

    // Get the FilterChain Here 
    ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance(); 
    ApplicationFilterChain filterChain = factory.createFilterChain(request, 
                  wrapper,servlet); 
    // Call the service() method for the allocated servlet instance 
    try { 
     String jspFile = wrapper.getJspFile(); 
     if (jspFile != null) 
      request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); 
     else 
      request.removeAttribute(Globals.JSP_FILE_ATTR); 
     support.fireInstanceEvent(InstanceEvent.BEFORE_DISPATCH_EVENT, 
            servlet, request, response); 
     // for includes/forwards 
     if ((servlet != null) && (filterChain != null)) { 
      filterChain.doFilter(request, response); 
     } 
     // Servlet Service Method is called by the FilterChain 
     request.removeAttribute(Globals.JSP_FILE_ATTR); 
     support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, 
            servlet, request, response); 
    } 
    ...exception handling here.... 

    // Release the filter chain (if any) for this request 
    try { 
     if (filterChain != null) 
      filterChain.release(); 
    } 
    ...exception handling here....   

    // Deallocate the allocated servlet instance 
    try { 
     if (servlet != null) { 
      wrapper.deallocate(servlet); 
     } 
    } 
    ...exception handling here.... 

    // Reset the old context class loader 
    if (oldCCL != null) 
     Thread.currentThread().setContextClassLoader(oldCCL); 

    // Unwrap request/response if needed 
    // See Bugzilla 30949 
    unwrapRequest(state); 
    unwrapResponse(state); 

    // Rethrow an exception if one was thrown by the invoked servlet 
    if (ioException != null) 
     throw ioException; 
    if (servletException != null) 
     throw servletException; 
    if (runtimeException != null) 
     throw runtimeException; 

} 

回答

3

如果你已经成型的应用程序,那么你真的回答了你自己的问题 - 如果没有可衡量的业绩命中使用<jsp:include>,那就不是值得担心。在内部,Tomcat将构建一个新的HttpServletRequest和相关的gubbins,但它可能足够聪明,可以保持轻量级。在实际观察之前,不要假设Feature X存在性能问题。

<jsp:include>的一个很好的选择是JSP 2.0 tag files。这些允许您封装可重用的内容,如使用<jsp:include>,但是为片段定义了明确的界面,并且不会产生<jsp:include>的开销(可能很小)。我更喜欢他们,我认为这是一个更优雅的方法。

(附加答案)有一个包含内嵌机制:<%@ include file="x.jsp" %>。这会执行包含内容的编译时内联。但是,您必须小心,因为如果在运行时更改x.jsp的内容,则“主机”页面将不会重新编译。

+1

该链接是给404一个替换或许? http://docs.oracle.com/javaee/1.4/tutorial/doc/JSPTags5.html – 2012-07-27 09:13:42