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