JSP: включить, производительность, модульность, альтернативы и лучшие практики, часть 96 - PullRequest
3 голосов
/ 29 июля 2010

Это продолжение вопроса 'overhead of jsp include' ниже:

Производительность JSP с использованием jsp: include

В нашем приложении разработчики имеют «модульные» фрагменты jsp, интенсивно используя «jsp: includes» для «общего» кода jsp, повторяемого в приложении.

1010 * Pros *

Плюсы:

  • это СУХОЙ - мы определяем фрагмент jsp один раз. Это большая помощь, когда вам нужно изменить html и не нужно искать / заменять / искать / уничтожать.

  • за ним довольно легко следить: вы четко передаете параметры. Когда вы редактируете «включенную» страницу, вы «знаете, что вы получаете», то есть против некоторых «глобальных переменных», объявленных на странице «включающие / вызывающие».

Против

  • накладные расходы на выполнение дополнительного запроса

Вопросы

Итак, как продолжение:

  • сколько накладных расходов несет «jsp: include»? Это не очевидно из кода Tomcat (хотя вы видите, что он делает гораздо больше, чем встроенный вызов). Также при профилировании приложения я никогда не запрашиваю методы requestDispatcher.include () или invoke () как горячие точки.
  • Может ли кто-нибудь указать, где именно находится основная часть накладных расходов? (то есть метод X в классе Y) Или это просто все "мелочи" (например, установка атрибутов или создание объектов и последующий сборщик мусора), которые происходят с каждым запросом?
  • какие есть альтернативы? (AFAIK @include и jsp: включить. Что-нибудь еще?)
  • (глупый бонусный вопрос), почему движок сервлета не может «включать» 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;

}

1 Ответ

3 голосов
/ 29 июля 2010

Если вы профилировали приложение, то вы действительно ответили на свой собственный вопрос - если нет ощутимого снижения производительности при использовании <jsp:include>, тогда об этом не стоит беспокоиться. Внутри Tomcat создаст новый HttpServletRequest и связанные с ним губбины, но он, вероятно, достаточно умен, чтобы сохранить его легким. Урок состоит в том, чтобы не предполагать, что с Feature X есть проблема с производительностью, пока вы на самом деле ее не заметили.

Хорошей альтернативой <jsp:include> является файлы тегов JSP 2.0 . Это позволяет вам инкапсулировать повторно используемый контент, например, с <jsp:include>, но с четко определенным интерфейсом для фрагмента, и без дополнительных издержек (какими бы маленькими они ни были) <jsp:include>. Я предпочитаю их, я думаю, что это более элегантный подход.

(Бонусный ответ) Существует встроенный механизм включения: <%@ include file="x.jsp" %>. Это выполняет встраивание во время компиляции включенного контента. Вы должны быть осторожны с этим, поскольку, если вы измените содержимое x.jsp во время выполнения, страница "host" не будет перекомпилирована.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...