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>
还有一个就是对于动态的servlet,设置
dynamic.setAsyncSupported(true);
就可以了
②而对于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。
下面的代码是网上的:
// 请求到 /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
dispatch(String path) 这个方法就是转发到指定的url上去
complete():在我们使用了request.startAsync(..)获得AsyncContext之后,在完成异步操作以后,需要调用这个方法结束异步的操作。如果请求分派到一个不支持异步操作的Servlet,或者由AsyncContext.dispatch调用的目标servlet之后没有调用complete,则complete方法会由容器调用。但是对于比合法操作来说,比如没有调用startAsync放方法,却代用complete() ,那么就会抛出IllegalStateException的异常,同时在调用complete()之前,调用dispath()方法是不起作用的,当然了,因为这个时候异步还没结束嘛,当然不会又什么作用了。
setTimeOut(..) 设置超时的时间 表示的是异步处理的最大时间,如果是一个负数的话,那么表示永远不会超时
start(Runnable run) Runnable表示的就是异步处理的任务。我们在做的时候 会AsyncContext 带进去 因为所以的操作 都需要依靠他呢
addListener(AsyncListener listener);增加监听器 就是监听AsyncContext各种状态发现变化的,主要有

前面三个都比较好理解,最后异步监听器将以它们添加到请求时的顺序得到通知。
下面是AsyncContext的一般使用方式
package com.hotusm.servlet.async; import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit; import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns={"/url"},asyncSupported=true)
public class AsynDemoServlet extends HttpServlet{ @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//resp.setHeader("Connection", "Keep-Alive");
resp.setContentType("text/html;charset=utf-8"); System.out.println(req.isAsyncSupported()+" "+req.isAsyncStarted());
/*req.getAsyncContext(); 表示的是最近的那个被request创建或者是
* 重转发的AsyncContext
*/ final AsyncContext ac = req.startAsync(); //设置超时的时间
ac.setTimeout(*1000L); //这种方式
ac.start(new Runnable() { public void run() { try {
TimeUnit.SECONDS.sleep(3L);
} catch (InterruptedException e) {
e.printStackTrace();
} try {
PrintWriter writer = ac.getResponse().getWriter();
writer.write("");
writer.flush(); //这是测试 同一个AsyncContext在没有调用complete 之前能不能多次的
//调用request 和response
PrintWriter writer1 = ac.getResponse().getWriter();
writer1.write("");
writer1.flush(); ServletRequest request = ac.getRequest(); request.setAttribute("isAsyn", true); /*
* 2.在调用完complete之后 表示这个异步已经结束了 如果在调用
* getRequest 或者是getResponse的话 都会抛出IllegalStateException
*
* */
ac.complete();
} catch (Exception e) {
e.printStackTrace();
}
}
});
//设置监听
ac.addListener(new AsyncListenerImpl()); // 在同一个request中不能同时调用多次
//req.startAsync();
PrintWriter out = resp.getWriter();
out.write("hello async");
out.write("<br/>");
//调用flush 不然还是不会输出 因为没有将内容刷出去
out.flush();
} static class AsyncListenerImpl implements AsyncListener{ public void onComplete(AsyncEvent event) throws IOException { System.out.println("onComplete");
} public void onTimeout(AsyncEvent event) throws IOException {
System.out.println("onTimeout");
event.getAsyncContext().complete();
} public void onError(AsyncEvent event) throws IOException {
System.out.println("onError");
} public void onStartAsync(AsyncEvent event) throws IOException {
System.out.println("onStartAsync");
}
}
}
当我们上面的url的时候 会马上返回hello async,然后在大概三秒钟之后,输出12
上面的方式只是使用了start(Runnable run);的方式.我们也可以将AsyncContext放到一个工作队列中去,然后另外的一个线程池去做处理。
示例代码:
package com.hotusm.servlet.async; import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue; 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(urlPatterns={"/async1"},asyncSupported=true)
public class AsyncDispatchServlet1 extends HttpServlet{ private LinkedBlockingQueue<AsyncContext> works=new LinkedBlockingQueue<AsyncContext>(); @Override
public void init() throws ServletException {
//因为这里是测试 所以就开了5个线程来进行处理 但是真实的情况下 肯定是设计一个伸缩性的方案
new Thread(new HelperWork()).start();
new Thread(new HelperWork()).start();
new Thread(new HelperWork()).start();
new Thread(new HelperWork()).start();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("Connection", "Keep-Alive");
resp.addHeader("Cache-Control", "private");
resp.addHeader("Pragma", "no-cache");
resp.setContentType("text/html;charset=utf-8");
try {
works.put(req.startAsync());
} catch (Exception e) { }
PrintWriter writer = resp.getWriter();
writer.write("等待异步完成");
writer.flush();
} private class HelperWork implements Runnable{ public void run() {
try {
AsyncContext ac = works.take();
//模拟业务消耗
TimeUnit.SECONDS.sleep(2L)
HttpServletRequest request = (HttpServletRequest)ac.getRequest();
Map<String, String[]> maps = request.getParameterMap();
System.out.println(maps); HttpServletResponse response = (HttpServletResponse)ac.getResponse();
PrintWriter writer = response.getWriter();
writer.write(maps.toString());
writer.flush();
ac.complete();
} catch (Exception e) {
e.printStackTrace();
} }
}
}
上面只是一种思路,我们还可以放入到线程池中进行处理等等。
然后再讲一下怎么通过ajax怎么异步的通信,我们只需要在第一次访问servlet的时候,保留AsyncContext的引用,之后通过这个的输出和页面做交互就可以了。
Servlet3.0的异步的更多相关文章
- Servlet3.0对异步处理的支持
Servlet工作流程 Servlet 3.0 之前,一个普通 Servlet 的主要工作流程大致如下: Servlet 接收到请求之后,可能需要对请求携带的数据进行一些预处理: 调用业务接口的某些方 ...
- 十三:Servlet3.0的异步
servlet之前的操作同时同步的,就是按照这样的一个流程来走的: 1.请求根据一个路径路由到一个servlet中, 2.servlet获取一系列的参数 3.执行一系列的逻辑(花费时间所占的比重也更大 ...
- Filter学习总结,顺便提及点servlet3.0异步filter和异步监听
Filter介绍: Filter在项目中经常可以用到,通常配置在web.xml中.是服务器端的一个组件,对于用户的请求和响应数据进行过滤操作,控制是否让用户访问到对应的web资源.常用于编 ...
- 深入理解Servlet3.0异步请求
异步请求的基础概念 异步请求最直接的用法就是处理耗时业务,Http协议是单向的,只能客户端拉不能服务器主推. 异步请求的核心原理主要分为两大类:1.轮询.2长连接 轮询:就是定时获取返回结果. 长连接 ...
- Servlet3.0的新特性
注意:Servlet3.0的项目一定要使用Tomcat7.0才能看到效果!! 1.新增标注支持 在Servlet3.0的部署描述文件web.xml的顶层标签<web-app>中有一 ...
- Servlet3.0新特性使用详解
可插拔的Web框架 几乎所有基于Java的web框架都建立在servlet之上.现今大多数web框架要么通过servlet.要么通过Web.xml插入.利用标注(Annotation)来定义servl ...
- Servlet3.0新特性(从注解配置到websocket编程)
Servlet3.0的出现是servlet史上最大的变革,其中的许多新特性大大的简化了web应用的开发,为广大劳苦的程序员减轻了压力,提高了web开发的效率.主要新特性有以下几个: 引入注解配置 支持 ...
- Servlet 3.0 对异步处理的支持
Servlet 3.0 实现了对异步处理的支持 通过利用注解@WebServlet(urlPatterns="/AServlet" AysnsSupported=true) 让后n ...
- Servlet3.0 新特性
Servlet3.0 的注解 Servlet 允许开发人员采用注解的方式来配置 Servlet.Filter.Listener. Servlet3.0 规范在 javax.servlet.annota ...
随机推荐
- css3圆形百分比进度条的实现原理
原文地址:css3圆形百分比进度条的实现原理 今天早上起来在查看jquery插件机制的时候,一不小心点进了css3圆形百分比进度条的相关文章,于是一发不可收拾,开始折腾了... 关于圆形圈的实现,想必 ...
- Android中实现APP文本内容的分享发送与接收方法简述
谨记(指定选择器Intent.createChooser()) 开始今天的内容前,先闲聊一下: (1)突然有一天头脑风暴,对很多问题有了新的看法和见解,迫不及待的想要分享给大家,文档已经写好了,我需要 ...
- 和我一起看API(一)你所不知道的LinearLayout补充
楼主英语水平差,翻译的不好的话请多多指正,嘿嘿... A Layout that arranges its children in a single column or a single row. T ...
- 两个变量交换的四种方法(Java)
对于两种变量的交换,我发现四种方法,下面我用Java来演示一下. 1.利用第三个变量交换数值,简单的方法. (代码演示一下) class TestEV //创建一个类 { public static ...
- [Django]用户权限学习系列之User权限基本操作指令
针对Django 后台自带的用户管理系统,虽说感觉还可以,但是为了方便用户一些操作,特别设计自定义的用户权限管理系统. 在制作权限页面前,首先需要了解权限和用户配置权限的指令,上章讲到权限的添加,删除 ...
- 《CPU的工作过程》
本文转载自inter官方网址:https://software.intel.com/zh-cn/articles/book-Processor-Architecture_CPU_work_proces ...
- Handler
1.1 继承AbstractController优点:能定制请求方式 package cn.happyl.controller; import javax.servlet.http.HttpServl ...
- 个人也能申请微信小程序获得APPID和手机测试效果
微信小程序昨晚火爆公测,我也第一时间注册了小程序账号开启公测之旅. 注册过程可以看文档:https://my.oschina.net/imhoodoo/blog/780901 进入后台之后我们其实主要 ...
- ASP.NET MVC 使用 Petapoco 微型ORM框架+NpgSql驱动连接 PostgreSQL数据库
前段时间在园子里看到了小蝶惊鸿 发布的有关绿色版的Linux.NET——“Jws.Mono”.由于我对.Net程序跑在Linux上非常感兴趣,自己也看了一些有关mono的资料,但是一直没有时间抽出时间 ...
- 监督学习 VS 无监督学习
监督学习 就是人们常说的分类,通过已有的训练样本(即已知数据以及其对应的输出)去训练得到一个最优模型(这个模型属于某个函数的集合,最优则表示在某个评价准则下是最佳的),再利用这个模型将所有的输入映射为 ...