【问题标题】:How to use a filter to measure performance?如何使用过滤器来衡量性能?
【发布时间】:2012-11-08 09:23:55
【问题描述】:

我想知道是否可以使用过滤器(在我的情况下为 CorsFilter)来测量时间并将所花费的时间放在消息本身上。我知道以下工作正常:

public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
  long startTime = System.nanoTime();
  chain.doFilter(request, response);
  long endTime = System.nanoTime();
  System.out.println("Time: " + (endTime - startTime) );
}

这当然会以秒为单位输出总时间。我想将时间放入返回响应的标头中,以便接收者可以查看标头并了解处理需要多长时间。以下代码不起作用:

public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
  long startTime = System.nanoTime();
  if(response instanceof HttpServletResponse) {
    HttpServletResponse httpResp = (HttpServletResponse)response;
    httpResp.addHeader("Start-time", Long.toString(startTime));
  }

  chain.doFilter(request, response);
  long endTime = System.nanoTime();
  if(response instanceof HttpServletResponse) {
    HttpServletResponse httpResp = (HttpServletResponse)response;
    httpResp.addHeader("End-time", Long.toString(endTime));
  }
}

标头仅包括开始时间而不包括结束时间。我假设这是因为消息已经发送,所以修改对象将无效。

有没有人有一个优雅/聪明的解决方案,通过使用过滤器将时间放入标题中?

谢谢, 菲尔

更新

我研究了使用 HttpServletResponseWrapper 来解决此解决方案。这仍然无法在响应标头上输出 XXX-EndTime 或 YYY-EndTime。

@Override
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
  long startTime = System.nanoTime();

  if(response instanceof HttpServletResponse) {
    HttpServletResponse httpResp = (HttpServletResponse)response;
    httpResp.addHeader("Access-Control-Allow-Origin", "*");
    httpResp.addHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
    httpResp.addHeader("Allow", "GET, HEAD, OPTIONS");
    httpResp.addHeader("Access-Control-Allow-Headers", "*");
    httpResp.addHeader("A-Runtime", Long.toString(startTime));
  }

  OutputStream out = response.getOutputStream();

  GenericResponseWrapper wrapper = new GenericResponseWrapper((HttpServletResponse) response);

  chain.doFilter(request,wrapper);

  out.write(wrapper.getData());

  if(response instanceof HttpServletResponse) {
HttpServletResponse httpResp = (HttpServletResponse)response;
httpResp.addHeader("XXX-EndTime", Long.toString(System.nanoTime() - startTime));

    wrapper.addHeader("YYY-EndTime", Long.toString(System.nanoTime() - startTime));
  }

  out.close();
}

【问题讨论】:

    标签: java servlets servlet-filters timing


    【解决方案1】:

    看看HttpServletResponseWrapper


    好的,那么代码:

    此代码缓冲输出(以两种方式),因此在伪输出之后添加标头有效。实际上 addHeader 可以通过输出来实现,所以我们 幸运 它起作用了。边界案例代码。如果不走运,addHeader 将不得不被覆盖。

    请注意,当我尝试时,在我的测试应用程序中只调用了 getOutputStream。可以选择 getPrintWriter 或 getOutputStream。

    private static class PostponingResponseWrapper extends HttpServletResponseWrapper {
    
        private ByteArrayOutputStream bos;
        private ServletOutputStream outputStream;
        private StringWriter sw;
        private PrintWriter printWriter;
        private boolean usingOutputStream;
        private boolean usingWriter;
    
        public PostponingResponseWrapper (HttpServletResponse response) {
            super(response);
            bos = new ByteArrayOutputStream();
            outputStream = new ServletOutputStream() {
                @Override
                public void write(int b) throws IOException {
                    bos.write(b);
                }
            };
            sw = new StringWriter();
            printWriter = new PrintWriter(sw);
        }
    
        @Override
        public PrintWriter getWriter() throws IOException {
            usingWriter = true;
            LOGGER.info("getWriter usingWriter {}, usingOutputStream {}", usingWriter, usingOutputStream);
            return printWriter;
        }
    
        @Override
        public void flushBuffer() throws IOException {
            LOGGER.info("flushBuffer");
        }
    
        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            usingOutputStream = true;
            LOGGER.info("getOutputStream usingWriter {}, usingOutputStream {}", usingWriter, usingOutputStream);
            ServletOutputStream out = new ServletOutputStream() {
                @Override
                public void write(int b) throws IOException {
                    outputStream.write(b);
                }
            };
            return out;
        }
    
        public void finish() throws IOException {
            LOGGER.info("finish");
            if (usingWriter) {
                super.getWriter().print(sw.toString());
            } else if (usingOutputStream) {
                super.getOutputStream().write(bos.toByteArray());
            }
        }
    }
    
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        PostponingResponseWrapper responseWrapper =
                new PostponingResponseWrapper (httpServletResponse);
        responseWrapper.addHeader("Before", "Already-Worked");
        chain.doFilter(request, responseWrapper);
        responseWrapper.addHeader("After", "And-Now-This");
        responseWrapper.finish(); // Writes the actual response
    }
    

    【讨论】:

    • @YevgeniyM。你是对的,应该只是一个评论,有这样一个包装类 +1。
    • 好的,我已经使用 HttpServletResponseWrapper 实现了一个解决方案,但仍然无法让它工作!我会用我的新代码更新上面的问题。
    • @YevgeniyM。添加了实际代码,因为您对原始答案非常满意。
    • @JoopEggen 你的努力将得到回报:)
    • 嗨乔普。感谢您的代码。我使用了您为我的解决方案提供的代码的变体。谢谢。
    猜你喜欢
    • 2011-10-02
    • 1970-01-01
    • 2022-11-11
    • 2019-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多