您的位置:首页 > 其它

异步处理Servlet接收到的请求

2015-06-11 13:32 323 查看
在Servlet组件接收到的每个请求都会产生一个线程来处理请求并返回响应,当客户端的请求处理是一项比较耗时的过程,当有大量用户请求此Servlet时,Web容器中就会产生大量的线程,导致Web容器性能急剧下降。为了解决这一问题,Servlet提供了对请求的异步处理支持。

异步处理请求的过程为:当Servlet接收到请求之后,首先需要对请求携带的数据进行一些预处理;接着,Servlet线程将请求转交给一个异步线程来执行业务处理,线程本身则返回至容器并可以处理其它客户端的请求,此时Servlet并没有差生响应数据,异步处理完业务以后,可以直接生成响应数据,或者将请求继续转发给其它Servlet。这样,Servlet线程不再是一直处于阻塞状态以等待业务逻辑的处理,而是启动异步线程之后可以立即返回。

使用异步处理,必须要配置相应的部署文件,在web.xml中通过使用<async-supported>标签设置是否需要启用异步处理支持,true表示支持,false表示不支持。当然我们也可以用注解的方式来替代在web.xml中的配置。注解则需要使用asyncSupported属性来支持异步处理。

下面我们看一个小Demo来掩饰Servlet组件的异步处理特性:

package com.yl.servlet;

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组件异步处理请求特性的演示小程序
 * 
 * @author LYYL
 *
 */
//通过注解的方式配置,支持异步处理请求
@WebServlet(name="servlet", urlPatterns={"/asyncServlet"}, asyncSupported=true)
public class AsyncServlet extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		processRequest(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		processRequest(req, resp);
	}
	
	protected void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException{
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter pw = response.getWriter();
		pw.println("进入Servlet的时间是:" + new Date() + ".");
		pw.flush();
		
		//在子线程中执行业务逻辑,并由其负责输出响应,主线程退出
		AsyncContext act = request.startAsync();
		//创建一个模拟业务逻辑执行的线程
		Executor ec = new Executor(act);
		Thread td = new Thread(ec);
		td.start();
		
		pw.println("<br>");
		pw.println("结束Servlet的时间是: " + new Date() + ".");
		pw.flush();	
	}
	/**
	 * 内部类,模拟线程执行的业务逻辑
	 * 
	 * @author LYYL
	 *
	 */
	public class Executor implements Runnable{
		private AsyncContext act = null;
		
		/**
		 * @param act
		 */
		public Executor(AsyncContext act) {
			this.act = act;
		}

		@Override
		public void run() {
			try {
				Thread.sleep(3000);
				PrintWriter pw = act.getResponse().getWriter();
				pw.println("<br>");
				pw.println("业务执行完的时间是: " + new Date() + ".");
				pw.flush();
				act.complete();
				pw.close();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
}


最终效果,Servlet开始和结束时间基本一致,而异步线程结束的时间也就是该Servlet执行完业务逻辑的时间是我们设定的3秒之后,如图:



注意:在通过request得到AsyncContext实例的时候用的是startAsync()方法,而不是request.getAsyncContext(),如果你用的是request.getAsyncContext()得到的实例为空,会在异步线程中报空指针异常。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: