zoukankan      html  css  js  c++  java
  • 十三:Servlet3.0的异步

    servlet之前的操作同时同步的,就是按照这样的一个流程来走的:

    1.请求根据一个路径路由到一个servlet中,

    2.servlet获取一系列的参数

    3.执行一系列的逻辑(花费时间所占的比重也更大)

    4.返回结果

    上面的问题出现在这一系列的操作都是同步的,所以这个请求必定是堵塞到所以任务都完成之后才返回的,

    这样将会很浪费资源,因为线程堵塞在那里,仅仅是等待任务的完成。但是在servlet3.0之后,我们基本上可以

    是这样做的

    1.请求根据一个路径路由到一个servlet中,

    2.将逻辑放入到异步队列中去

    3.返回结果

    4.异步队列处理任务,得出结果,返回给页面

    而servet3.0对于异步的处理主要涉及的有两个特性,一个是新增的类AsyncContext,另外的一个就是asyncSupported属性

    ①如果我们想要让我们的servlet支持异步的话,那么asyncSupported这个属性是一定需要设置的,对于注解的类型来说,我们直接设置属性

    @WebServlet(asyncSupported=true,urlPatterns={"/async"})

    就可以了,对于老版本的配置问价来说,只需要在配置web.xml 的servlet那里增加一个

    <async-supported>true</async-supported> 
    ②而对于AsyncContext 需要记住的东西还是蛮多的,但是它主要的是保留了请求和相应的引用,在前面提到的返回结果之后的操作就是通过在异步环境下,对这两个引用进行操作。

    要获取这个就需要使用request在3.0之后增加的方法,startAsync(..) ,这个方法就是返回一个AsyncContext实体对象,这里包含了request和response的引用,直接使用AsyncContext.start(Runnable)方法启动一个新的线程去进行处理逻辑
    AsyncContext主要的方法:
    getRequest() 获得请求即request,我们可以在异步的环境像在service中使用一样

    getReponse() 和上面差不多一个意思

    hasOriginalRequestAndResponse()这个方法表示的是我们使用的AsyncContext是使用原始的请求获取的,还是通过封装过的请求和相应创建的
    简单的讲就是 原始的类型表示的是调用startAsync()。但是封装的就是startAsync(ServletRequest, ServletResponse)或者其他类型啦,

    dispatch()方法,这个方法有有好几个重载,表示的是转发,和req.getRequestDispatcher()有点类似,但是比较丰富
    如果使用的是startAsync(ServletRequest, ServletResponse)初始化AsyncContext,且传入的请求是HttpServletRequest的一个实例,则使用HttpServletRequest.getRequestURI()返回的URI进行分派。否则分派的是容器最后分派的请求URI。
    下面的代码是网上的:dispatch(String path) 这个方法就是转发到指定的url上去
    // 请求到 /url/A  
    AsyncContext ac = request.startAsync();  
    ...  
    ac.dispatch(); // 异步分派到 /url/A  
    
    // 请求到 /url/A  
    // 转发到 /url/B  
    request.getRequestDispatcher(“/url/B”).forward(request, response);  
    // 从FORWARD的目标内启动异步操作  
    AsyncContext ac = request.startAsync();  
    ac.dispatch(); // 异步分派到 /url/A  
    
    // 请求到 /url/A  
    // 转发到 /url/B  
    request.getRequestDispatcher(“/url/B”).forward(request, response);  
    // 从FORWARD的目标内启动异步操作  
    AsyncContext ac = request.startAsync(request, response);  
    ac.dispatch(); //异步分派到 /url/B

    complete():在我们使用了request.startAsync(..)获得AsyncContext之后,在完成异步操作以后,需要调用这个方法结束异步的操作。如果请求分派到一个不支持异步操作的Servlet,或者由AsyncContext.dispatch调用的目标servlet之后没有调用complete,则complete方法会由容器调用。

    setTimeOut(..) 设置超时的时间 表示的是异步处理的最大时间,如果是一个负数的话,那么表示永远不会超时

    start(Runnable run) Runnable表示的就是异步处理的任务。我们在做的时候 会AsyncContext  带进去 因为所以的操作 都需要依靠他呢

    addListener(AsyncListener listener);增加监听器  就是监听AsyncContext各种状态发现变化的,主要有

    前面三个都比较好理解,最后异步监听器将以它们添加到请求时的顺序得到通知。

    下面是AsyncContext的一般使用方式

    1. 模拟注册发信息到邮件的简单的异步处理 Servlet 示例代码:

    package com.servlet;
    
    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(value="/asyn-servlet",asyncSupported=true)
    public class ServletAsyn extends HttpServlet {
        private static final long serialVersionUID = 1L;
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                throws ServletException, IOException {
            System.out.println("Servlet is start");
            
            //1.获得异步上下文对象
            AsyncContext ac = request.startAsync();
            //2.启动一个耗时的子线程
            ThreadTask tt = new ThreadTask(ac);
            //3.可设置异步超时对象,需在启动异步上下文对象前设置
            /*
             * 设置超时后,在超时时间内子线程没有结束,主线程则会停止等待,继续往下执行
             */
            ac.setTimeout(3000);
            //4.开启异步上下文对象
            ac.start(tt);
            
            //主线程结束向客户端发送消息
            System.out.println("Servlet is end");
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().append("信息已发送到邮箱");
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request, response);
        }
    
    }

    异步线程的执行类:

    package com.servlet;
    
    import java.util.Date;
    
    import javax.servlet.AsyncContext;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    public class ThreadTask implements Runnable{
        private AsyncContext ac;  //定义一个异步上下文
        
        public ThreadTask(AsyncContext ac) {
            super();
            this.ac = ac;
        }
    
        @Override
        public void run() {
            /*
             * 服务端异步典型应用是注册时向邮箱发送验证码
             */
            try {
                //进行异步的一些处理
                HttpServletRequest requst = (HttpServletRequest) ac.getRequest();
                HttpSession session = requst.getSession();
                System.out.println("asyn-task start" + new Date());
                for(int i=5;i>0; i--) {
                    System.out.println(i);
                    Thread.sleep(1000);
                }
                //将结果放到session等方式
                session.setAttribute("message", "This is the result of asyn");
                System.out.println("asyn-task end" + new Date());
                
                //通知主线程已经处理完成
                /* 
                 * 除了使用 ac.complete() 方法通知主线程已经处理外
                 * 还可以使用 ac.dispatch() 方法重定向到一个页面
                 */
                ac.dispatch("/show.jsp");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
    }
  • 相关阅读:
    首页下拉广告代码
    索引 CREATE INDEX
    苏三起解 故事
    日期正则表达式
    除去非空字符串函数
    数据库什么是字段应该设置索引
    警务通
    动态生成缩略图
    超级实用且不花哨的js代码大全
    无线警务移动办公系统解决方案
  • 原文地址:https://www.cnblogs.com/deityjian/p/11468111.html
Copyright © 2011-2022 走看看