3.7 监听器
应用程序事件功能使Web应用程序开发人员可以更好地控制ServletContext、HttpSession和ServletRequest的生命周期,实现更好的代码分解,并提高管理Web应用程序使用的资源的效率。
事件监听器是实现一个或多个Servlet事件监听器接口的类。它们在部署Web应用时实例化并注册到Web容器中。它们由开发人员在WAR包中提供。
Servlet事件监听器支持在ServletContext、HttpSession和ServletRequest状态改变时进行事件通知。Servlet上下文监听器用来管理应用的资源或JVM级别持有的状态。HTTP会话监听器用来管理从相同客户端或用户进入Web应用的一系列请求关联的状态或资源。Servlet请求监听器用来管理整个Servlet请求生命周期的状态。异步监听器用来管理异步事件,例如超时和完成异步处理。
可以有多个监听器类监听每一个事件类型,且开发人员可以为每一个事件类型指定容器调用监听器Bean的顺序。
3.7.1 事件类型和监听器接口
事件类型和监听器接口总结如下:
1.Servlet上下文事件
Servlet上下文事件总结如表3-2所示。
表3-2 Servlet上下文事件
2.HTTP会话事件
HTTP会话事件总结如表3-3所示。
表3-3 HTTP会话事件
3.Servlet请求事件
Servlet请求事件总结如表3-4所示。
表3-4 Servlet请求事件
3.7.2 部署描述符示例
以下示例是注册两个Servlet上下文生命周期监听器和一个HttpSession监听器的部署语法。
假设com.waylau.java.MyConnectionManager和com.waylau.java.MyLoggingModule两个都实现了javax.servlet.ServletContextListener,且com.waylau.java.MyLoggingModule又实现了javax.servlet.http.HttpSessionListener。此外,开发人员希望com.waylau.java.MyConnectionManager在com.waylau.java.MyLoggingModule得到Servlet上下文生命周期事件的通知。下面是这个应用的部署描述符:
3.7.3 监听器实例和线程
容器需要在开始执行进入应用的第一个请求之前完成Web应用中的监听器类的实例化。容器必须保持到每一个监听器的引用直到为Web应用最后一个请求提供服务。
ServletContext和HttpSession对象的属性改变可能会同时发生。不要求容器同步到属性监听器类产生的通知。维护状态的监听器类负责数据的完整性且应明确处理这种情况。
3.7.4 监听器异常
一个监听器里面的应用代码在运行期间可能会抛出异常。一些监听器通知发生在应用中的另一个组件调用树的过程中。这方面的一个例子是一个Servlet设置了会话属性,该会话监听器抛出未处理的异常。容器必须允许未处理的异常由错误页面机制处理。如果没有为这些异常指定错误页面,容器就必须确保返回一个状态码为500的响应。这种情况下,不再有监听器根据事件被调用。
有些异常不会发生在应用中的另一个组件调用栈的过程中。这方面的一个例子SessionListener接收通知的会话已经超时并抛出未处理的异常,或者ServletContextListener在Servlet上下文初始化通知期间抛出未处理的异常,或者ServletRequestListener在初始化或销毁请求对象的通知期间抛出未处理的异常。这种情况下,开发人员没有机会处理这种异常。容器能够以HTTP状态码500来响应所有后续到Web应用的请求,表示应用出错了。
3.7.5 分布式容器
在分布式Web容器中,HttpSession实例被限到特定的JVM服务会话请求,且ServletContext对象被限定到Web容器所在的JVM。分布式容器不需要传播Servlet上下文事件或HttpSession事件到其他JVM。监听器类实例被限定到每个JVM的每个部署描述符声明一个。
3.7.6 会话事件
监听器类提供给开发人员一种跟踪Web应用内会话的方式。它通常是有用的,在跟踪会话时能够知道一个会话是否已经失效。会话失效有多种原因,可能是因为容器会话超时,或因为应用内的一个Web组件调用了invalidate方法。通过会话事件就能区别到底是什么原因导致的会话失效。