23spring注解学习——servlet3.0异步和spring的异步
Posted Arbitrary233
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了23spring注解学习——servlet3.0异步和spring的异步相关的知识,希望对你有一定的参考价值。
servlet3.0异步:
加上asyncSupported=true使支持异步
package com.atguigu.servlet; import java.io.IOException; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(value="/async",asyncSupported=true) public class HelloAsyncServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1、支持异步处理asyncSupported=true //2、开启异步模式 System.out.println("主线程开始。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis()); AsyncContext startAsync = req.startAsync(); //3、业务逻辑进行异步处理;开始异步处理 startAsync.start(new Runnable() { @Override public void run() { try { System.out.println("副线程开始。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis()); sayHello(); startAsync.complete(); //获取到异步上下文 AsyncContext asyncContext = req.getAsyncContext(); //4、获取响应 ServletResponse response = asyncContext.getResponse(); response.getWriter().write("hello async..."); System.out.println("副线程结束。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis()); } catch (Exception e) { } } }); System.out.println("主线程结束。。。"+Thread.currentThread()+"==>"+System.currentTimeMillis()); } public void sayHello() throws Exception{ System.out.println(Thread.currentThread()+" processing..."); Thread.sleep(3000); } }
执行结果如下:
如上截图可以看出servlet3.0的异步和servlet用的是同一个线程池
springmvc的异步(spring会给副线程再建一个线程池)
package com.atguigu.controller; import java.util.UUID; import java.util.concurrent.Callable; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.context.request.async.DeferredResult; import com.atguigu.service.DeferredResultQueue; @Controller public class AsyncController { @ResponseBody @RequestMapping("/createOrder") public DeferredResult<Object> createOrder(){ DeferredResult<Object> deferredResult = new DeferredResult<>((long)3000, "create fail..."); DeferredResultQueue.save(deferredResult); return deferredResult; } @ResponseBody @RequestMapping("/create") public String create(){ //创建订单 String order = UUID.randomUUID().toString(); DeferredResult<Object> deferredResult = DeferredResultQueue.get(); deferredResult.setResult(order); return "success===>"+order; } /** * 1、控制器返回Callable * 2、Spring异步处理,将Callable 提交到 TaskExecutor 使用一个隔离的线程进行执行 * 3、DispatcherServlet和所有的Filter退出web容器的线程,但是response 保持打开状态; * 4、Callable返回结果,SpringMVC将请求重新派发给容器,恢复之前的处理; * 5、根据Callable返回的结果。SpringMVC继续进行视图渲染流程等(从收请求-视图渲染)。 * * preHandle.../springmvc-annotation/async01 主线程开始...Thread[http-bio-8081-exec-3,5,main]==>1513932494700 主线程结束...Thread[http-bio-8081-exec-3,5,main]==>1513932494700 =========DispatcherServlet及所有的Filter退出线程============================ ================等待Callable执行========== 副线程开始...Thread[MvcAsync1,5,main]==>1513932494707 副线程开始...Thread[MvcAsync1,5,main]==>1513932496708 ================Callable执行完成========== ================再次收到之前重发过来的请求======== preHandle.../springmvc-annotation/async01 postHandle...(Callable的之前的返回值就是目标方法的返回值) afterCompletion... 异步的拦截器: 1)、原生API的AsyncListener 2)、SpringMVC:实现AsyncHandlerInterceptor; * @return */ @ResponseBody @RequestMapping("/async01") public Callable<String> async01(){ System.out.println("主线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis()); Callable<String> callable = new Callable<String>() { @Override public String call() throws Exception { System.out.println("副线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis()); Thread.sleep(2000); System.out.println("副线程开始..."+Thread.currentThread()+"==>"+System.currentTimeMillis()); return "Callable<String> async01()"; } }; System.out.println("主线程结束..."+Thread.currentThread()+"==>"+System.currentTimeMillis()); return callable; } }
执行结果如下:
发现拦截器的preHandle执行了两次(原因即为:spring主线程结束后会再次访问该路径,从而继续执行副线程,如最后的图)
以上是关于23spring注解学习——servlet3.0异步和spring的异步的主要内容,如果未能解决你的问题,请参考以下文章