Servlet中的异步处理

Servlet 3引入了异步处理特性,允许Servlet在新的线程中执行耗时任务,避免阻塞主线程。文章介绍了如何开启异步处理、设置超时时间、使用AsyncContext以及监听器。示例代码展示了如何编写异步Servlet,包括发送进程更新和处理异步事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Servlet 3引入一项新的特性,可以让Servlet异步处理请求,本文来介绍这新技术


一.概述

WebServlet  和 WebFilter  注解类型可以包含  asyncSupport属性。为了编写能够支持异步的Servlet和Filter ,该

属性必须为true


支持异步处理的Servlet或者Filter 可以通过在ServletRequest 中调用startAsync 方法来启动新的线程。

startAsync 有两个重载方法:

AsyncContext  startAsync ()

AsyncContext startAsync(ServletRequest request ,ServletResponse response)


注意:重复调用startAsync方法将会启动同一个线程,将会抛出一个java.lang.lllegalStateException 异常

         调用 AsyncContext的start方法不会造成阻塞,因此它派发的线程还没启动,也会继续执行下一行代码


二.编写异步的Servlet

如果你有一个任务需要相对比较长的时间才能完成,最好成绩一个Servlet或者Filter  。在异步的Servlet或者Filter类中

需要完成以下工作:

1.在ServletRequest 中调用startAsync 方法来启动新的线程

2.在AsyncContext中调用setTimeout()方法,设置一个任务必须在指定的时间内完成的毫秒数

3.调用asyncContext.start方法,传递一个执行长时间任务的Runnable

4.任务完成时,通过Runnable调用asyncContext.complete方法或者asyncContext.dispatch方法


举个例子

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(name="AsyncDispatchServlet",
urlPatterns="/asyncDispatch",
asyncSupported=true)
public class AsyncDispatchServlet extends HttpServlet {

	private static final long serialVersionUID=222L;
	
	@Override
	protected void doGet(final HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		final AsyncContext asyncContext=req.startAsync();
		req.setAttribute("mainThread", Thread.currentThread().getName());
		asyncContext.setTimeout(5000);
		asyncContext.start(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				try{
					Thread.sleep(4000);
				}catch(InterruptedException e){
					
				}
				req.setAttribute("workerThread", Thread.currentThread().getName());
				asyncContext.dispatch("/threadNames.jsp");
			}
		});
	}
}

上述代码在任务里休眠3秒。将主线程和工作线程发送到test.jsp页面,显示他们的线程名称

<body>
   Main thread:${mainThread}
   <br>
   Worker Thread:${workerThread}
  </body>


三.发送进程更新的异步


这个Servlet每秒钟发送一次进程更新,以便用户能够追踪进程

mport java.io.IOException;
import java.io.PrintWriter;

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(asyncSupported=true,urlPatterns="/asyncComplete")
public class AsyncCompleteServlet extends HttpServlet {
	private static final long serialVersionUID=78234L;
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		resp.setContentType("text/html");
		final PrintWriter write=resp.getWriter();
		write.println("<html><head><title>"
				+"Async Servlet</title></head>");
		write.println("<body><div id='progress'></div>");
		final AsyncContext asyncContext=req.startAsync();
		asyncContext.setTimeout(60000);
		asyncContext.start(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println("new Thread:"+Thread.currentThread());
				for(int i=0;i<10;i++){
					write.println("<script>");
					write.print("document.getElementById('progress').innerHTML='"
							+(i*10)+"% complete'");
					write.println("</script>");
					write.flush();
					try{
						Thread.sleep(1000);
					}catch(InterruptedException e){}
				}
				write.println("<script>");
				write.println("document.getElementById('progress').innerHTML='DONE'");
				write.println("</script>");
				write.println("</body></html>");
				asyncContext.complete();
			}
		});
	}

}





四.同步监听器


 除了Servlet和Filter执行异步操作之外,Servlet 3.0还新增了一个AsyncListener接口,以便通知用户在异步处理期间

发生的情况。


AsyncListener接口定义的方法:

void onStartAsync(AsyncEvent event)   在刚启动一个异步操作时调用

void onComplete(AsyncEvent event)   当一个异步操作已经完成时调用

void onError(AsyncEvent event)   当一个异步操作失败是调用

void onTimeout(AsyncEvent event)   当一个异步操作已经超时的时候调用


这四个方法都会受到一个AsyncEvent事件,可以通过调用它的getAsyncContext,getSuppliedRequest .getSuppliedResponse

方法从中获取相关的AsyncContext,ServletRequest,ServletResponse实例


举个例子:MyAsyncListener类实现了AsyncListener接口,以便当异步操作中有事件发生时能够受到通知,

与其他监听器不同,它没有用@WebListener标注AsyncListener的实现


import java.io.IOException;

import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
//do not annotate with @WebListener
public class MyAsyncListener implements AsyncListener {

	@Override
	public void onComplete(AsyncEvent arg0) throws IOException {
		// TODO Auto-generated method stub

		System.out.println("onComplete");
	}

	@Override
	public void onError(AsyncEvent arg0) throws IOException {
		// TODO Auto-generated method stub

		System.out.println("onError");
	}

	@Override
	public void onStartAsync(AsyncEvent arg0) throws IOException {
		// TODO Auto-generated method stub

		System.out.println("onStartAsync");
	}

	@Override
	public void onTimeout(AsyncEvent arg0) throws IOException {
		// TODO Auto-generated method stub

		System.out.println("onTimeout");
	}

}



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(name="AsyncListenerServlet",urlPatterns="/asyncListener",
asyncSupported=true)
public class AsyncListenerServlet extends HttpServlet {
	@Override
	protected void doGet(final HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		final AsyncContext asyncContext=req.startAsync();
		asyncContext.setTimeout(5000);
		
		asyncContext.addListener(new MyAsyncListener());
		asyncContext.start(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				try{
					Thread.sleep(3000);
					
				}catch(InterruptedException  e){
					
				}
				String greeting="hi from listener";
			    System.out.println("wait....");
			    req.setAttribute("greeting", greeting);
			    asyncContext.dispatch("/index.jsp");
			}
		});
	}

	
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值