Javaweb Servlet基础学习记录(6)—异步处理
在Servlet的原始版本中,假设浏览器同时有多个请求发送到服务器,web服务器在处理第一个请求时,若处理占用时间较长,则其他请求在这第一个请求被处理的时间段内无法进行任何操作。
被阻塞的Servlet请求过程:
Servlet3.0有了新特性异步处理,所谓异步处理就是指数据发送方发送数据给数据接收方后,不必等待数据接收方作出响应,可以继续发送下一个数据的通信方式,Servlet 3.0版本提供了相关异步处理的功能,具体实现方式如下:
- 需要使用注解在对应Servlet配置asyncSupported=true,表示当前Servlet支持异步。
- 通过Request对象的startAsync(Request, Response)方法获取异步上下文对象。
- 通过异步上下文对象调用start(new Runnable(){})方法开始异步处理,Runnable类的run()方法提供具体异步的逻辑代码。
Servlet异步处理流程:
演示:
package com;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
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;
/**
* Servlet implementation class AsyncDemoServlet
*/
@WebServlet(urlPatterns = "/AsyncDemoServlet", asyncSupported = true)
public class AsyncDemoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public AsyncDemoServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("<p>进入servlet时间" + new Date().toLocaleString() + "</p>");
AsyncContext asctx = request.startAsync();
new Thread(new Executor(asctx)).start();
out.print("<p>退出servlet时间" + new Date().toLocaleString() + "</p>");
out.flush();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
class Executor implements Runnable {
private AsyncContext ctx = null;
public Executor(AsyncContext asCtx) {
ctx = asCtx;
}
@Override
public void run() {
try {
Thread.sleep(10000);
PrintWriter out = ctx.getResponse().getWriter();
out.print("<p>子线程执行完毕" + new Date().toLocaleString() + "</p>");
out.flush();
ctx.complete();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
其中:
(1)在”WebServlet“注释中配置属性支持异步操作:@WebServlet(urlPatterns = "/AsyncDemoServlet", asyncSupported = true)
;
(2)创建子线程构建耗时操作:
class Executor implements Runnable {
private AsyncContext ctx = null;
//借助构造方法进行传参
public Executor(AsyncContext asCtx) {
ctx = asCtx;
}
@Override
//线程真正的操作在run方法中
public void run() {
try {
//模拟耗时操作
Thread.sleep(10000); //睡10秒
PrintWriter out = ctx.getResponse().getWriter();
out.print("<p>子线程执行完毕" + new Date().toLocaleString() + "</p>");
out.flush();
ctx.complete();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
(3)主线程:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter(); //记录进入时间
out.print("<p>进入servlet时间" + new Date().toLocaleString() + "</p>");
AsyncContext asctx = request.startAsync();
new Thread(new Executor(asctx)).start(); //启动线程
out.print("<p>退出servlet时间" + new Date().toLocaleString() + "</p>");
out.flush();
}
运行
仍在执行请求
进入与退出时间基本一致,主线程不会产生线程阻塞
- Servlet是运行在Servlet容器中的Java类,它能处理Web客户的HTTP请求,并产生HTTP响应;
- Servlet技术具有高效、方便、功能强大、可移植性好等特点;
- Servlet接口规定了必须由Servlet类实现并且由Servlet引擎识别和管理的方法集;
- Servlet API包含两个软件包: javax.servlet包和javax.servlet.http包;
- 简单地扩展GenericServlet和实现service()方法就可以编写一个基本的 Servlet,但若要实现一个在Web中处理HTTP的Servlet,则需要继承HttpServlet类;
- Servlet生命周期是指Servlet实例从创建到响应客户请求直至销毁的过程;
- Servlet的生命周期按照七种状态间的转换,可分为四个阶段:加载和实例化、初始化、处理请求、终止服务;
- Servlet既可使用注解@WebServlet进行配置,也可在web.xml文件中配置;
- 在Servlet中可以通过两种主要方式完成对新URL地址的转向:重定向和请求转发;
- Servlet 3.0较之前版本,新增了注解支持、可插性支持、动态配置和异步处理等新特性。