Servlet中的异步处理

    xiaoxiao2021-04-14  44

     Servlet 3引入一项新的特性,可以让Servlet异步处理请求,本文来介绍这新技术

    一.概述

    WebServlet  和 WebFilter  注解类型可以包含  asyncSupport属性。为了编写能够支持异步的Servlet和Filter ,该

    属性必须为true

    支持异步处理的Servlet或者Filter 可以通过在ServletRequest 中调用startAsync 方法来启动新的线程。

    startAsync 有两个重载方法:

    AsyncContext  startAsync ()

    AsyncContext startAsync(ServletRequest request ,ServletResponse response)

    注意:重复调用startAsync方法将会启动同一个线程,将会抛出一个java.lang.lllegalStateException 异常

             调用 AsyncContext的start方法不会造成阻塞,因此它派发的线程还没启动,也会继续执行下一行代码

    二.编写异步的Servlet

    如果你有一个任务需要相对比较长的时间才能完成,最好成绩一个Servlet或者Filter  。在异步的Servlet或者Filter类中

    需要完成以下工作:

    1.在ServletRequest 中调用startAsync 方法来启动新的线程

    2.在AsyncContext中调用setTimeout()方法,设置一个任务必须在指定的时间内完成的毫秒数

    3.调用asyncContext.start方法,传递一个执行长时间任务的Runnable

    4.任务完成时,通过Runnable调用asyncContext.complete方法或者asyncContext.dispatch方法

    举个例子

    import java.io.IOException; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="AsyncDispatchServlet", urlPatterns="/asyncDispatch", asyncSupported=true) public class AsyncDispatchServlet extends HttpServlet { private static final long serialVersionUID=222L; @Override protected void doGet(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub final AsyncContext asyncContext=req.startAsync(); req.setAttribute("mainThread", Thread.currentThread().getName()); asyncContext.setTimeout(5000); asyncContext.start(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try{ Thread.sleep(4000); }catch(InterruptedException e){ } req.setAttribute("workerThread", Thread.currentThread().getName()); asyncContext.dispatch("/threadNames.jsp"); } }); } }

    上述代码在任务里休眠3秒。将主线程和工作线程发送到test.jsp页面,显示他们的线程名称

    <body> Main thread:${mainThread} <br> Worker Thread:${workerThread} </body>

    三.发送进程更新的异步

    这个Servlet每秒钟发送一次进程更新,以便用户能够追踪进程

    mport java.io.IOException; import java.io.PrintWriter; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(asyncSupported=true,urlPatterns="/asyncComplete") public class AsyncCompleteServlet extends HttpServlet { private static final long serialVersionUID=78234L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub resp.setContentType("text/html"); final PrintWriter write=resp.getWriter(); write.println("<html><head><title>" +"Async Servlet</title></head>"); write.println("<body><div id='progress'></div>"); final AsyncContext asyncContext=req.startAsync(); asyncContext.setTimeout(60000); asyncContext.start(new Runnable() { @Override public void run() { // TODO Auto-generated method stub System.out.println("new Thread:"+Thread.currentThread()); for(int i=0;i<10;i++){ write.println("<script>"); write.print("document.getElementById('progress').innerHTML='" +(i*10)+"% complete'"); write.println("</script>"); write.flush(); try{ Thread.sleep(1000); }catch(InterruptedException e){} } write.println("<script>"); write.println("document.getElementById('progress').innerHTML='DONE'"); write.println("</script>"); write.println("</body></html>"); asyncContext.complete(); } }); } }

    四.同步监听器

     除了Servlet和Filter执行异步操作之外,Servlet 3.0还新增了一个AsyncListener接口,以便通知用户在异步处理期间

    发生的情况。

    AsyncListener接口定义的方法:

    void onStartAsync(AsyncEvent event)   在刚启动一个异步操作时调用

    void onComplete(AsyncEvent event)   当一个异步操作已经完成时调用

    void onError(AsyncEvent event)   当一个异步操作失败是调用

    void onTimeout(AsyncEvent event)   当一个异步操作已经超时的时候调用

    这四个方法都会受到一个AsyncEvent事件,可以通过调用它的getAsyncContext,getSuppliedRequest .getSuppliedResponse

    方法从中获取相关的AsyncContext,ServletRequest,ServletResponse实例

    举个例子:MyAsyncListener类实现了AsyncListener接口,以便当异步操作中有事件发生时能够受到通知,

    与其他监听器不同,它没有用@WebListener标注AsyncListener的实现

    import java.io.IOException; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; //do not annotate with @WebListener public class MyAsyncListener implements AsyncListener { @Override public void onComplete(AsyncEvent arg0) throws IOException { // TODO Auto-generated method stub System.out.println("onComplete"); } @Override public void onError(AsyncEvent arg0) throws IOException { // TODO Auto-generated method stub System.out.println("onError"); } @Override public void onStartAsync(AsyncEvent arg0) throws IOException { // TODO Auto-generated method stub System.out.println("onStartAsync"); } @Override public void onTimeout(AsyncEvent arg0) throws IOException { // TODO Auto-generated method stub System.out.println("onTimeout"); } }

    import java.io.IOException; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="AsyncListenerServlet",urlPatterns="/asyncListener", asyncSupported=true) public class AsyncListenerServlet extends HttpServlet { @Override protected void doGet(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub final AsyncContext asyncContext=req.startAsync(); asyncContext.setTimeout(5000); asyncContext.addListener(new MyAsyncListener()); asyncContext.start(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try{ Thread.sleep(3000); }catch(InterruptedException e){ } String greeting="hi from listener"; System.out.println("wait...."); req.setAttribute("greeting", greeting); asyncContext.dispatch("/index.jsp"); } }); } }
    转载请注明原文地址: https://ju.6miu.com/read-670348.html

    最新回复(0)