8.4 ServletRequestListeners ServletRequest范围的监听器接口有三个:ServletRequestListener、ServletRequestAttributeListener和AsyncListener。前两个接口会在本节进行介绍,而AsyncListener接口则会在第11章中进行介绍。
8.4.1 ServletRequestListener ServletRequestListener监听器会对ServletRequest的创建和销毁事件进行响应。容器会通过一个池来存放并重复利用多个ServletRequest,ServletRequest的创建时刻是从容器池里被分配出来的时候,而它的销毁时刻是放回容器池里的时间。ServletRequestListener接口有两个方法,requestInitialized和requestDestroyed:
1 2 void requestInitialized (ServletRequestEvent event) void requestDestroyed (ServletRequestEvent event)
当一个ServletRequest创建(从容器池里取出)时,requestInitialized方法会被调用,当ServletRequest销毁(被容器回收)时,requestDestroyed方法会被调用。这两个方法都会接收到一个ServletRequestEvent对象,可以通过使用这个对象的getServletRequest方法来获取ServletRequest对象:
1 ServletRequest getServletRequest ()
另外,ServletRequestEvent接口也提供了一个getServletContext方法来获取ServletContext,如下所示:
1 ServletContext getServletContext ()
实例 以app08a项目里的PerfStatListener类为例。这个监听器用来计算每个ServletRequest从创建到销毁的生存时间。
PerfStatListener实现了ServletRequestListener接口,来计算每个HTTP请求的完成时间。由于容器在请求创建时会调用ServletRequestListener的requestInitialized方法,在销毁时会调用requestDestroyed,因此很容易就可以计算出时间。只需要在记录下两个事件的事件,并且相减,就可以计算出一次HTTP请求的完成时间了。
PerfStatListener 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package app08a.listener;import javax.servlet.ServletRequest;import javax.servlet.ServletRequestEvent;import javax.servlet.ServletRequestListener;import javax.servlet.annotation.WebListener;import javax.servlet.http.HttpServletRequest;@WebListener public class PerfStatListener implements ServletRequestListener { @Override public void requestInitialized (ServletRequestEvent sre) { ServletRequest servletRequest = sre.getServletRequest(); servletRequest.setAttribute("start" , System.nanoTime()); } @Override public void requestDestroyed (ServletRequestEvent sre) { ServletRequest servletRequest = sre.getServletRequest(); Long start = (Long) servletRequest.getAttribute("start" ); Long end = System.nanoTime(); HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; String uri = httpServletRequest.getRequestURI(); System.out.println("time taken to execute " + uri + ":" + ((end - start) / 1000 ) + " microseconds" ); } }
方法说明 requestInitialized方法 requestInitialized方法调用System.nanoTime()获取当前系统时间的数值(Long类型),并将这个数值保存到ServletRequest中:
1 2 3 4 5 6 7 8 @Override public void requestInitialized (ServletRequestEvent sre) { ServletRequest servletRequest = sre.getServletRequest(); servletRequest.setAttribute("start" , System.nanoTime()); }
nanoTime返回一个long类型的数值来表示任意时间。这个数值和系统或是时钟时间都没什么关系,但是同一个JVM上调用两次nanoTime得到的数值可以计算出两次调用之间的时间。
requestDestroyed方法 在requestDestroyed方法中再次调用nanoTime方法,并且减去第一次调用获得的数值,就得到HTTP请求的完成时间了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Override public void requestDestroyed (ServletRequestEvent sre) { ServletRequest servletRequest = sre.getServletRequest(); Long start = (Long) servletRequest.getAttribute("start" ); Long end = System.nanoTime(); HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; String uri = httpServletRequest.getRequestURI(); System.out.println("time taken to execute " + uri + ":" + ((end - start) / 1000 ) + " microseconds" ); }
运行效果 调用app08a应用中的countries.jsp页面,在控制台中可以看到PerfStatListener的运行效果,下面是几次调用时控制台的输出:
1 2 3 4 time taken to execute /app08a/countries.jsp:31243 microseconds time taken to execute /app08a/countries.jsp:6671 microseconds time taken to execute /app08a/countries.jsp:4701 microseconds time taken to execute /app08a/countries.jsp:4242 microseconds
原文链接: 8.4 ServletRequestListeners 8.4.1 ServletRequestListener