Servlet工作流程

Servlet 3.0 之前,一个普通 Servlet 的主要工作流程大致如下:

  1. Servlet 接收到请求之后,可能需要对请求携带的数据进行一些预处理;
  2. 调用业务接口的某些方法,以完成业务处理;
  3. 最后,根据处理的结果提交响应,Servlet 线程结束。

servlet是单例多线程的,当servlet线程池满了的时候,后续访问该Servlet的请求只能进行等待

其中第二步的业务处理通常是最耗时的,这主要体现在数据库操作,以及其它的跨网络调用等,在此过程中,Servlet 线程一直处于阻塞状态,直到业务方法执行完毕。在处理业务的过程中,Servlet 资源一直被占用而得不到释放,对于并发较大的应用,这有可能造成性能的瓶颈。对此,在以前通常是采用私有解决方案来提前结束 Servlet 线程,并及时释放资源。

Servlet3.0异步处理

Servlet 3.0 针对这个问题做了开创性的工作,现在通过使用 Servlet 3.0 的异步处理支持,之前的 Servlet 处理流程可以调整为如下的过程:

  1. 首先,Servlet 接收到请求之后,可能首先需要对请求携带的数据进行一些预处理;
  2. 接着,Servlet 线程将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,此时 Servlet 还没有生成响应数据,异步线程处理完业务以后,可以直接生成响应数据(异步线程拥有 ServletRequest 和 ServletResponse 对象的引用),或者将请求继续转发给其它 Servlet。如此一来, Servlet 线程不再是一直处于阻塞状态以等待业务逻辑的处理,而是启动异步线程之后可以立即返回。

代码示例一:

首先创建一个动态的web工程

public class DemoThread implements Runnable {
private PrintWriter out; public DemoThread(PrintWriter out) {
this.out = out;
} @Override
public void run() {
out.println("子线程---运行<br>");
int sum = 0;
for (int i = 0; i < 10; i++) {
System.out.println("i = " + i);
sum += i;
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
out.println("sum = " + sum + "<br>");
out.println("子线程---结束<br>");
}
}
@WebServlet("/demo")
public class DemoServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("主线程开始运行<br>");
new Thread(new DemoThread(out)).start();
out.print("主线程运行结束<br>");
}
}

使用Servelt3.0注解方式创建的一个DemoServlet,我们运行tomcat容器并访问这个Servlet

观察控制台:

这与我们需要的展示效果相差甚远 :主线程直接就结束了,子线程依旧在运行


注意:

异步处理特性可以应用于 Servlet 和过滤器两种组件,由于异步处理的工作模式和普通工作模式在实现上有着本质的区别,因此默认情况下,Servlet 和过滤器并没有开启异步处理特性,如果希望使用该特性,则必须按照如下的方式启用:

我们开启Servelt异步处理后,改写代码观察结果:

// asyncSupported 默认为false,
@WebServlet(value = "/demo",asyncSupported = true)
public class DemoServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("进入Servlet的时间:" + new Date() + "<br>"); //在子线程中执行业务调用,并由其负责输出响应,主线程退出
AsyncContext ctx = request.startAsync();
new Thread(new DemoThread(ctx)).start();
out.println("结束Servlet的时间:" + new Date() + "<br>");
}
}
public class DemoThread implements Runnable {

    private AsyncContext ctx = null;

    public DemoThread(AsyncContext ctx) {
this.ctx = ctx;
} @Override
public void run() {
int sum = 0;
try {
// 通过此种方式就能获取到响应流
PrintWriter out = ctx.getResponse().getWriter();
out.println("子线程---运行<br>");
sum = 0;
for (int i = 0; i < 10; i++) {
System.out.println("i = " + i);
sum += i;
Thread.sleep(1000L);
}
out.println("sum = " + sum + "<br>");
out.println("子线程---结束<br>");
out.println("业务处理完毕的时间:" + new Date() + "<br>");
ctx.complete();
} catch (Exception e) {
e.printStackTrace();
}
}
}

观察时间可以发现,Servlet线程运行完就结束了,返回到线程池,大大节省了资源,如果有多个请求,就能够处理接下来的请求。而我们的DemoThread线程依旧能够生成响应数据

Servlet3.0对异步处理的支持的更多相关文章

  1. Servlet 3.0 对异步处理的支持

    Servlet 3.0 实现了对异步处理的支持 通过利用注解@WebServlet(urlPatterns="/AServlet" AysnsSupported=true) 让后n ...

  2. Servlet3.0的异步

    servlet之前的操作同时同步的,就是按照这样的一个流程来走的: 1.请求根据一个路径路由到一个servlet中, 2.servlet获取一系列的参数 3.执行一系列的逻辑(花费时间所占的比重也更大 ...

  3. 十三:Servlet3.0的异步

    servlet之前的操作同时同步的,就是按照这样的一个流程来走的: 1.请求根据一个路径路由到一个servlet中, 2.servlet获取一系列的参数 3.执行一系列的逻辑(花费时间所占的比重也更大 ...

  4. 深入理解Servlet3.0异步请求

    异步请求的基础概念 异步请求最直接的用法就是处理耗时业务,Http协议是单向的,只能客户端拉不能服务器主推. 异步请求的核心原理主要分为两大类:1.轮询.2长连接 轮询:就是定时获取返回结果. 长连接 ...

  5. Filter学习总结,顺便提及点servlet3.0异步filter和异步监听

      Filter介绍:     Filter在项目中经常可以用到,通常配置在web.xml中.是服务器端的一个组件,对于用户的请求和响应数据进行过滤操作,控制是否让用户访问到对应的web资源.常用于编 ...

  6. Servlet3.0新特性使用详解

    可插拔的Web框架 几乎所有基于Java的web框架都建立在servlet之上.现今大多数web框架要么通过servlet.要么通过Web.xml插入.利用标注(Annotation)来定义servl ...

  7. Servlet3.0新特性(从注解配置到websocket编程)

    Servlet3.0的出现是servlet史上最大的变革,其中的许多新特性大大的简化了web应用的开发,为广大劳苦的程序员减轻了压力,提高了web开发的效率.主要新特性有以下几个: 引入注解配置 支持 ...

  8. Javaweb学习笔记——(二十八)——————Servlet3.0、动态代理、类加载器

    web最后一天:完了. Servlet3.0          一.要求         1.MyEclipse10.0或以上版本         2.发布到Tomcat7.0或以上版本 二.步骤   ...

  9. Servlet3.0 新特性

    Servlet3.0 的注解 Servlet 允许开发人员采用注解的方式来配置 Servlet.Filter.Listener. Servlet3.0 规范在 javax.servlet.annota ...

随机推荐

  1. swift函数式编程之compose

    func a(en:String) -> String { return en + "a"; } func b(en:String) -> String { retur ...

  2. linux修改镜像

    修改为163yum源-mirrors.163.com 1.首先备份系统自带yum源配置文件/etc/yum.repos.d/CentOS-Base.repo [root@localhost ~]# m ...

  3. zabbix_server [22842]: cannot open log: cannot create semaphore set: [28] No space left on device

    zabbix server服务没启动,查看日志显示 zabbix_server [22842]: cannot open log: cannot create semaphore set: [28] ...

  4. Java实现PV操作 | 哲学家进餐问题

    运行结果: Java代码: public class Main { public static void main(String[] args) { Global global=new Global( ...

  5. js 队列

    js 中的异步队列(micro & macro) js都是靠事件驱动的, js中的事件循环机制是什么呢? 只是简单写一下自己的理解, 所以不是很全面; js 程序执行有 主队列 以及 异步队列 ...

  6. 表格样式、表格css、

    .mytab{ border-collapse: collapse;}.mytab tr,.mytab td,.mytab th{ text-align: center; border: 1px so ...

  7. docker删除名称为<none>的镜像

    docker rmi $(docker images | awk '/^<none>/ { print $3 }')

  8. 转载【MySQL】MySQL5.X常用日志配置及5.7和5.6主从复制的区别

    转载:https://blog.csdn.net/zyb378747350/article/details/78728886 2)MySQL5.7和5.6主从复制的区别: . 5.6之后默认binlo ...

  9. mybatis ResultHandler vs ResultSetHandler及自定义扩展

    ResultSetHandler是mybatis的关键类之一,用于对jdbc返回的ResultSet进行映射处理,其中包括列前缀处理,逻辑分页,鉴别器(Discriminator,基于值实现动态映射列 ...

  10. 使用ssh-keygen生成私钥和公钥

    1.使用ssh-keygen生成私钥和公钥 命令如下: ssh-keygen -t rsassh-keygen -t rsa -C "用户名自取"可以是邮箱 例子: fdipzon ...