Servlet3.0的异步支持-AsyncContext

版权声明:原创文章,未经允许不得转载.Tips:传统电商火热的时代已经成为过去 , 下一个阶段属于大数据 人工智能 , 服务、便捷、安全、效率、创新成为下一个阶段互联网时代的新词汇,而IT技术也随着行业的变化发展而不断更迭。对于码农的出路总结一句话:追技术不如追领域。[基础][设计][能力] https://blog.csdn.net/shengqianfeng/article/details/84667056

Servlet3是Tomcat7出现的新特性,所以使用的tomcat版本不能低于7.0.

由于每个request请求进来之后都被分配了一个线程处理,如果当前处理的业务方法非常耗时,将会在某段时间出现非常多的线程,而其他请求无法被分配到线程执行而被拒绝,所以Servlet3.0引入了异步支持,请求进来后交给另外一个工作线程去执行,释放当前接入请求的线程,这样就可以接入越来越多的请求,提高并发量。

if (request.isAsyncSupported()) {
			
			//用于启动异步工作线程,进入异步模式,调用业务处理线程进行业务处理
			request.startAsync(request, response);
			if (request.isAsyncStarted()) {
				/**
				 * 1 获取AsyncContext,对异步执行的上下文提供支持,可以透过AsyncContext的getRequest() 、 getResponse()方法取得Request、Response对象
				 * 2  客户端的响应将暂缓至,调用AsyncContext的complete()方法或dispatch()为止,前者表示回应完成,后者表示将响应调派给指定的URL
				 * 3 使用异步处理方式,web容器的请求处理线程释放了,可以服务其他的请求处理。但是该Request的处理并没有结束,
				 *   在使用AsyncContext的complete或者dispatch完成后,这个request的处理才结束。
				 * 
				 */
				final AsyncContext asyncContext = request.getAsyncContext();
				asyncContext.setTimeout(SysConfig.getInstance().getPropertyInt("async_timeout"));
				// Servlet不会被阻塞,而是直接往下执行
				asyncContext.start(
				// 开启http线程
				new Runnable() {
					@Override
					public void run() {

						PrintWriter printWriter = null;
						try {
							logger.info("休眠3秒钟...");
							Thread.sleep(3000);
							String responseMsgContent = "";
							String ws_callback = SysConfig.getInstance().getProperty("ws_callback");
							String result = HttpUtils.postHttpAndHttps(ws_callback, "desc="+System.currentTimeMillis()+"-"+RandomUtils.nextInt(0, 9999));
							logger.info("线程Name:{},result:{}",Thread.currentThread().getName(),result);
							response.setCharacterEncoding("UTF-8");
							response.setHeader("Content-type","application/json;charset=UTF-8");
							printWriter = response.getWriter();
							printWriter.write(responseMsgContent);
							logger.info(responseMsgContent);
						} catch (Exception e) {
							e.printStackTrace();
						} finally {
							if (printWriter != null) {
								printWriter.flush();
								printWriter.close();
							}
							//告诉启动异步处理的Servlet异步处理已完成,Servlet就会提交请求响应
							asyncContext.complete();
						}
					}

				});
				logger.info("继续执行....");
			}
		} else { // 不支持异步
			logger.info("当前servlet容器不支持异步....");
		}

以上的asyncContext.start(new Runnable(){});这个方法是将任务提交给了主线程池,这样的话感觉不过还是使用的主线程池的线程数,可能效果不是很好。

我们也可以使用自定义线程池,将需要异步处理的任务提交给线程池管理,灵活调用。

package com.jeff.nio.controller;

import java.io.PrintWriter;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.jeff.nio.server.common.JsonDto;


/**
 * 登录
 *
 */
@Controller
public class TestController {

	private static final Logger logger = LoggerFactory.getLogger(TestController.class);

	private static ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 200, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(100));

	@GetMapping(value="/servlet3.0/asyncContext")
	public @ResponseBody void startServer(HttpServletRequest request, HttpServletResponse response) {
		JsonDto jsonDto = new JsonDto();
		try {
			logger.info("start server...................");
			if (request.isAsyncSupported()) {
				//用于启动异步工作线程,进入异步模式,调用业务处理线程进行业务处理
				request.startAsync(request, response);
				if (request.isAsyncStarted()) {
					/**
					 * 1 获取AsyncContext,对异步执行的上下文提供支持,可以透过AsyncContext的getRequest() 、 getResponse()方法取得Request、Response对象
					 * 2  客户端的响应将暂缓至,调用AsyncContext的complete()方法或dispatch()为止,前者表示回应完成,后者表示将响应调派给指定的URL
					 * 3 使用异步处理方式,web容器的请求处理线程释放了,可以服务其他的请求处理。但是该Request的处理并没有结束,
					 *   在使用AsyncContext的complete或者dispatch完成后,这个request的处理才结束。
					 * 
					 */
					final AsyncContext asyncContext = request.getAsyncContext();
					asyncContext.setTimeout(5000);
					// Servlet不会被阻塞,而是直接往下执行
					executor.execute(new Runnable() {
						@Override
						public void run() {
							PrintWriter printWriter = null;
							try {
								logger.info("休眠3秒钟...");
								Thread.sleep(3000);
								response.setCharacterEncoding("UTF-8");
								response.setHeader("Content-type","application/json;charset=UTF-8");
								printWriter = response.getWriter();
								printWriter.write(jsonDto.toString());
							} catch (Exception e) {
								e.printStackTrace();
							} finally {
								if (printWriter != null) {
									printWriter.flush();
									printWriter.close();
								}
								//告诉启动异步处理的Servlet异步处理已完成,Servlet就会提交请求响应
								asyncContext.complete();
							}
						}
					});
					logger.info("继续执行....");
				}
			} else { // 不支持异步
				logger.info("当前servlet容器不支持异步....");
			}
		} catch (Exception e) {
			e.printStackTrace();
			jsonDto.setCode("-1");
			jsonDto.setMsg("执行失败");
		}
	}
}

猜你喜欢

转载自blog.csdn.net/shengqianfeng/article/details/84667056