java-jsp:include,性能,模块化,替代方法和最佳实践,第96部分

这是下面“ jsp包含的开销”问题的后续措施:

JSP Performance using jsp:include

在我们的应用程序中,开发人员通过大量使用“ jsp:includes”来“模块化” jsp片段,以在整个应用程序中重复使用“通用” jsp代码.

优点

专业人士如下:

>很干燥-我们定义一次jsp片段.当您需要更改一些html而不需要查找/替换/搜索/销毁时,这是一个很大的帮助.
>相当容易遵循:您清楚地传递了参数.当您编辑“包含”页面时,您“知道自己要得到什么”,即与“包含/调用”页面中声明的一些“全局变量”相对.

缺点

>附加请求的性能开销

问题

因此,作为后续:

>’jsp:include’会产生多少性能开销?从tomcat代码中并不明显(尽管您看到的功能比内联调用要多得多).另外,在对应用程序进行性能分析时,我从来不会将requestDispatcher.include()或invoke()方法显示为热点.
>有人可以指出大部分开销在哪里吗? (即类Y中的方法X)还是每个请求都发生了所有的“小事情”(例如,设置属性或对象创建以及后续的GC)?
>有哪些替代方案? (AFAIK @include和jsp:include.还有其他吗?)
>(愚蠢的奖励问题)为什么servlet引擎在编译时不能“包含” jsp,即像“带有参数的内联宏”那样,以便我们开发人员可以清楚地看到“ jsp: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&gt ;,但为该片段定义了明确的接口,并且不会产生< jsp:include>的开销(无论多么小). .我更喜欢它们,我认为这是一种更优雅的方法.

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

上一篇:LINQ示例的复杂性是什么?


下一篇:java-检查连接速度的库