2010-07-10 1 views
13

Я понимаю, что это проблема с курицей и яйцом, и невозможно точно определить время, необходимое для отображения страницы (или размера ответа), и вставить это число в саму страницу, не затрагивая ни одну из мер. Тем не менее, я ищу способ вставить любой номер частично на страницу приложения JSF/Facelets/Seam.Как вставить время рендеринга страницы JSF и размер ответа на страницу, по крайней мере частично?

Э.Г., в нижней части страницы .jsf где-то:

<!-- page size: 10.3Kb --> 
<!-- render time: 0.2s --> 

Я пришел через JSFUnit-х JSFTimer, что очень удобно. Однако подход фазового прослушивателя не позволяет вставлять результаты фазы RENDER_RESPONSE в страницу. Не уверен, как получить доступ к размеру зашифрованного ответа до сих пор.

Есть ли быстрый и грязный способ подключиться к какому-либо событию после обработки в конце или после окончания RENDER_RESPONSE и ввести оба числа на страницу, подлежащую визуализации? Один из способов приблизиться к этому - возможно, через фильтры сервлетов, но я ищу что-то более простое; возможно, трюк с пластами или Facelets ...

Спасибо,
-A

ответ

22

Это идеальный вариант использования для Apache Commons IOCountingOutputStream. Вам необходимо создать Filter, который использует HttpServletResponseWrapper, чтобы заменить OutputStream ответа на этот номер и заменить также Writer, который должен обернуть обернутый OutputStream. Затем возьмите экземпляр HttpServletResponseWrapper в области запроса, чтобы вы могли получить getByteCount() от CountingOutputStream.

Вот зарезка пример CountingFilter:

public class CountingFilter implements Filter { 

    @Override 
    public void init(FilterConfig arg0) throws ServletException { 
     // NOOP. 
    } 

    @Override 
    public void doFilter(ServletRequest request, final ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     HttpServletResponse httpres = (HttpServletResponse) response; 
     CountingServletResponse counter = new CountingServletResponse(httpres); 
     HttpServletRequest httpreq = (HttpServletRequest) request; 
     httpreq.setAttribute("counter", counter); 
     chain.doFilter(request, counter); 
     counter.flushBuffer(); // Push the last bits containing HTML comment. 
    } 

    @Override 
    public void destroy() { 
     // NOOP. 
    } 

} 

CountingServletResponse:

public class CountingServletResponse extends HttpServletResponseWrapper { 

    private final long startTime; 
    private final CountingServletOutputStream output; 
    private final PrintWriter writer; 

    public CountingServletResponse(HttpServletResponse response) throws IOException { 
     super(response); 
     startTime = System.nanoTime(); 
     output = new CountingServletOutputStream(response.getOutputStream()); 
     writer = new PrintWriter(output, true); 
    } 

    @Override 
    public ServletOutputStream getOutputStream() throws IOException { 
     return output; 
    } 

    @Override 
    public PrintWriter getWriter() throws IOException { 
     return writer; 
    } 

    @Override 
    public void flushBuffer() throws IOException { 
     writer.flush(); 
    } 

    public long getElapsedTime() { 
     return System.nanoTime() - startTime; 
    } 

    public long getByteCount() throws IOException { 
     flushBuffer(); // Ensure that all bytes are written at this point. 
     return output.getByteCount(); 
    } 

} 

CountingServletOutputStream:

public class CountingServletOutputStream extends ServletOutputStream { 

    private final CountingOutputStream output; 

    public CountingServletOutputStream(ServletOutputStream output) { 
     this.output = new CountingOutputStream(output); 
    } 

    @Override 
    public void write(int b) throws IOException { 
     output.write(b); 
    } 

    @Override 
    public void flush() throws IOException { 
     output.flush(); 
    } 

    public long getByteCount() { 
     return output.getByteCount(); 
    } 

} 

Вы можете использовать его в любой (даже без JSF) следующим образом:

<!DOCTYPE html> 
<html 
    xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html"> 
    <h:head> 
     <title>Counting demo</title> 
    </h:head> 
    <h:body> 
     <h1>Hello World</h1> 
    </h:body> 
</html> 
<!-- page size: #{counter.byteCount/1000}KB --> 
<!-- render time: #{counter.elapsedTime/1000000}ms --> 
+0

Насколько я хотел избежать фильтров, это выглядит как лучший подход. Спасибо за предложение! Вот некоторые вещи, о которых нужно знать: 1) с помощью шва, фильтры довольно легко настроить с помощью аннотаций, например: @Scope (APPLICATION) @Name ("org.myorg.countingFilter") @BypassInterceptors @Filter (вокруг = "org.jboss.seam.web.ajax4jsfFilter") CountingFilter 2) из-за проблемы с курицей/яйцом, отмеченной выше, цифры не совсем точны. В JSF ViewState не учитывается byteCount, что может быть значительным числом. То же самое относится к времени рендеринга. Оба они достаточно хороши для грубой картины. – anikitin

+0

Великий материал снова. Однако у меня есть несколько запросов обратной передачи, которые генерируют несколько ответов. Как найти правильный ответ, то есть тот, который я имел в виду? – Kawu

+0

@Kawu: измените шаблон URL фильтра таким образом, чтобы он работал только по желаемым URL-адресам. – BalusC

0

Или есть асинхронная Javascript вызова, который получает время и размера ответа от сервера после его готовности? Относитесь к нему, как обратный вызов, который нужно выполнить после того, как страница будет загружена, и значения готовы к вставке.

2

Я написал сообщение в блоге, объясняющее, как вы могли бы создать перехватчик, который будет измерять каждый метод, называть ваши шовными компонентами, где они используются.

Вы можете найти сообщение в блоге here. Вам нужно прокрутить страницу до второй части.

В принципе, все, что вам нужно сделать, это аннотирования метод, который вы хотите измерить с @MeasureCalls и он будет автоматически подобран перехватчика

@Name("fooBean") 
@MeasureCalls 
public class FooBean 

Выход будет что-то вроде этого, показывая время потребовалось в миллисекундах и сколько раз каждый метод назывался:

284.94 ms 1 FooBean.getRandomDroplets() 
284.56 ms 1 GahBean.getRandomDroplets() 
201.60 ms 2 SohBean.searchRatedDoodlesWithinHead() 
185.94 ms 1 FroBean.doSearchPopular() 
157.63 ms 1 FroBean.doSearchRecent() 
42.34 ms 1 FooBean.fetchMostRecentYodel() 
41.94 ms 1 GahBean.getMostRecentYodel() 
15.89 ms 1 FooBean.getNoOfYodels() 
15.00 ms 1 GahBean.getNoOfYodels() 
    9.14 ms 1 SohBean.mainYodels() 
    1.11 ms 2 SohBean.trackHoorayEvent() 
    0.32 ms 1 FroBean.reset() 
    0.22 ms 43 NohBean.thumbPicture() 
    0.03 ms 18 FooBean.getMostRecentYodels() 
    0.01 ms 1 NohBean.profilePicture() 
    0.01 ms 1 FroBean.setToDefault() 
    0.01 ms 1 FroBean.getRecentMarker() 
+0

404 страница не найдена. – BalusC

+0

Спасибо @BalusC, ссылка обновлена ​​ –

+0

Выглядит удобно. Подсказка для вашего 'toString()': есть 'Class # getSimpleName()' и 'String # format()'. – BalusC