java - jsp:include,性能,模块化,备选方案和最佳实践,第 96 部分

标签 java performance jsp servlets include

这是下面“jsp include 的开销”问题的后续:

JSP Performance using jsp:include

在我们的应用程序中,开发人员通过大量使用“jsp:includes”来“模块化”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;

}

最佳答案

如果您分析了该应用程序,那么您就真正回答了自己的问题 - 如果使用 <jsp:include> 没有可衡量的性能影响,那就不值得担心了。在内部,Tomcat 将构建一个新的 HttpServletRequest和相关的 gubbins,但它可能足够聪明,可以保持轻量化。教训是,在您实际观察到它之前,不要假设功能 X 存在性能问题。

<jsp:include> 的一个很好的替代品是JSP 2.0 tag files .这些允许您封装可重用的内容,例如 <jsp:include> ,但具有明确定义的片段接口(interface),并且不会产生 <jsp:include> 的开销(无论多么小) .我更喜欢它们,我认为这是一种更优雅的方法。

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

关于java - jsp:include,性能,模块化,备选方案和最佳实践,第 96 部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3357891/

相关文章:

java - 安卓工作室 : 'C:\Program Files\Java\jdk1.8.0_51\bin\java.exe' ' finished with non-zero exit value 1

c# - Parallel.For() 会随着重复执行而变慢。我应该看什么?

java - 如何根据参数值在jsp文件中使用动态CSS

Java等级计算器。我需要一些帮助来开始这个类

java - 必须指定spring security的authenticationManager

java - 添加第二列导致错误

c++ - 提高 std::sort 性能

java - 如何提高 Solr 性能?

java - 显示带有 url 模式 "/*"的转发 JSP

java - 选择下拉选项时插入数据,MySQL、JAVA、JSP