Servlet的监听器 Servlet的监听器即Listener,它能够监听来自client的请求、完毕server端的操作等。通过监听器,能够自己主动触发一些操作。比方:监听在线用户的数量,当添加一个HttpSession时,就触发一个sessionCreated(HttpSessionEvent se)方法。这样就能够给在线人数加1了。
经常使用的监听器接口有:
1. ServletContextListener
监听ServletContext。当创建ServletContext时。触发contextInitialized(ServletContextEvent sce)方法;当销毁ServletContext时。触发contextDestroyed(ServletContextEvent sce)方法。
2. ServletContextAttributeListener
监听对ServletContext属性的操作,比方添加、删除、改动属性。
3. HttpSessionListener
监听HttpSession的操作。当创建一个Session时,触发session Created(HttpSessionEvent se)方法。当销毁一个Session时,触发sessionDestroyed(HttpSessionEvent se)方法。
4. HttpSessionAttributeListener
监听HttpSession属性的操作。当在Session添加一个属性时,触发attributeAdded(HttpSessionBindingEvent se)方法;当在Session删除一个属性时。触发attributeRemoved(HttpSessionBindingEvent se)方法。当在Session属性被又一次设置时。触发attributeReplaced(HttpSessionBindingEvent se)方法。
Servlet 3.0的监听器跟Servlet 2.5的监听器区别不大。唯一的区别就是添加了对注解的支持。在3.0曾经,监听器的配置须要配置到web.xml文件。在3.0中,监听器的配置既能够放入web.xml文件,还能够使用注解进行配置。对于使用注解的监听器就是在监听器类上使用@WebListener进行凝视,这样Web容器就会把这个类当成是一个监听器进行注冊和使用。
假设是採用web.xml配置文件的方式,那么就是这样: <listener> <listener-class>com.xxx.SessionListener</listener-class> </listener> <listener> <listener-class>com.xxx.ContextListener</listener-class> </listener> Servlet 3.0的异步处理有时Filter或Servlet在生成响应之前必须等待一些耗时的操作结果以便完毕请求处理。而在Servlet中。等待是一个低效的操作。由于这是堵塞操作。会白白占用一个线程或其它一些受限资源。 很多线程为了等待一个缓慢的资源(如数据库连接)经常发生堵塞。可能引起线程饥饿,从而减少整个Web容器的服务质量。
Servlet 3.0引入了异步处理请求的能力,使线程能够返回到容器。从而运行很多其它的任务。当開始异步处理请求时,还有一个线程或回调能够或产生响应。或调用完毕(complete)或请求分派(dispatch)。这样。它能够在容器上下文使用AsyncContext.dispatch方法运行。
一个典型的异步处理事件顺序是:
1. 请求被接收到,通过一系列如用于验证的标准Filter之后被传递到Servlet。
2. Servlet处理请求參数及内容体从而确定请求的类型。
3. 该Servlet发出请求去获取一些资源或数据。
4. Servlet不产生响应并返回。
5. 过了一段时间后,所请求的资源变为可用,此时处理线程继续处理事件。要么在同一个线程,要么通过AsyncContext分派到容器中的某个资源上。
@WebServlet凝视和@WebFilter凝视有一个属性——asyncSupported,是布尔类型,默认值为false。当asyncSupported设置为true,则应用通过运行startAsync能够启动一个单独的线程进行异步处理,并把请求和响应的引用传递给这个线程,然后退出原始线程所在的容器。这意味着响应将遍历(相反的顺序)与进入时同样的过滤器(或过滤器链)。 直到AsyncContext调用complete时响应才会被提交。假设异步任务在容器启动的分派之前运行。且调用了startAsync并返回给容器,此时应用需负责处理请求和响应对象的并发訪问。
从一个 Servlet分派时,把asyncSupported=true设置为false是同意的。这样的情况下。当Servlet的Service方法不支持异步退出时,响应会被提交,且容器负责调用AsyncContext的complete。以便全部感兴趣的AsyncListener能得到触发通知。过滤器作为清理要完毕的异步任务持有资源的一种机制。也应该使用AsyncListener.onComplete触发。
从一个同步Servlet分派到还有一个异步Servlet是非法的。只是与该点不同的是当应用调用startAsync时将抛出IllegalStateException。这将同意 servlet 仅仅能作为同步的或异步的 Servlet。
应用在一个与初始请求所用的不同的线程中等待异步任务直到能够直接写响应,这个线程不知道不论什么过滤器。假设过滤器想处理新线程中的响应,那就必须在处理进入时的初始请求时包装 response。而且把包装的 response 传递给链中的下一个过滤器,并终于交给 Servlet。因此,假设响应是包装的(可能被包装多次。每个过滤器一次),而且应用处理请求并直接写响应,这将仅仅写响应的包装对象,即不论什么输出的响应都会由响应的包装对象处理。
当应用在一个单独的线程中读请求时。写内容到响应的包装对象,这事实上是从请求的包装对象读取。并写到响应的包装对象,因此对包装对象操作的全部输入及(或)输出将继续存在。假设应用选择这样做的话,它将能够使用 AsyncContext 从一个新线程发起到容器资源的分派请求。 这将同意在容器范围内使用像 JSP 这样的内容生成技术。 异步监听器接口AsyncListener Servlet 3.0为异步处理提供了一个监听器,使用AsyncListener接口表示。此接口负责管理异步事件。它能够监控例如以下四种事件:
1. 异步线程開始时。调用AsyncListener的onStartAsync(AsyncEvent event)方法。
2. 异步线程出错时,调用AsyncListener的onError(AsyncEvent event)方法。
3. 异步线程运行超时,则调用AsyncListener的onTimeout(AsyncEvent event)方法。
4. 异步运行完毕时,调用AsyncListener的onComplete(AsyncEvent event)方法; 要注冊一个AsyncListener。仅仅需将准备好的AsyncListener对象传递给AsyncContext对象的addListener()方法就可以。例如以下所看到的: @Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse res){ AsyncContext actx = req.startAsync(); actx.addListener(new AsyncListener(){ public void onComplete(AsyncEvent event) throws IOException{ // do 一些清理工作或者其它 } public void onTimeout(AsyncEvent event) throws IOException{ // do 一些超时处理的工作或者其它 } }); ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10); executor.execute(new MyAsyncService(actx)); }
|