DeferedResult处理流程
Spring mvc的控制层接收用户的请求之后,如果要采用异步处理,那么就要返回DeferedResult<>泛型对象。在调用完控制层之后,立即回返回DeferedResult对象,此时驱动控制层的容器主线程,可以处理更多的请求。
可以将DeferedResult对象作为真实响应数据的代理,而真实的数据是该对象的成员变量result,它可以是String类型,或者ModelAndView类型等。
容器主线程,会调用DeferedResult对象的getResult方法,然后响应到客户端。在业务没有处理完毕时,result真实数据还没有形成,那么容器主线程会发生阻塞。
业务处理完毕之后,要执行setResult方法,将真实的响应数据赋值到DeferedResult对象中。此时,异步线程会唤醒容器主线程。那么容器主线程会继续执行getResult方法,将真实数据响应到客户端。
也可以有这样的应用场景。在Spring Mvc的控制层中,只要有一个用户请求便会实例化一个DeferedResult对象,然后返回该对象,进行响应客户端。只要DeferedResult对象不设置result响应的内容,则控制层的容器主线程在响应客户端上就会发生阻塞。因为SpringMVC只会实例化一个Controller对象,无论有多少个用户请求,在堆上只有一个Controller对象,因此可以添加一个成员变量List,将这些用户请求的DeferedResult对象存放到List中,然后启动一个定时线程扫描list,从而依次执行setResult方法,响应客户端。
目前主流的spring servlet的配置是使用java 代码进行配置.所以本文的带配置方式也是基于java 代码对servlet
进行配置,支持异步.
依赖: 主要保证你的servlet版本大于等于3.0
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency>
(1).配置servlet开启对异步的支持
在实现了WebApplicationInitializer接口的类中加入
ServletRegistration.Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(ctx)); servlet.setLoadOnStartup(1); servlet.addMapping("/"); //主要是加入此句,开始对异步的支持 servlet.setAsyncSupported(true);
web.xml方式的配置不多说,百度一大堆.
(2). controller中使用异步
@Controllerpublic class DeferedResultController { private ConcurrentLinkedDeque<DeferredResult<String>> deferredResults = new ConcurrentLinkedDeque<DeferredResult<String>>(); @RequestMapping("/getResult") @ResponseBody public DeferredResult<String> getDeferredResultController(){ //设置 5秒就会超时 final DeferredResult<String> stringDeferredResult = new DeferredResult<String>(1000); //将请求加入到队列中 deferredResults.add(stringDeferredResult); final String message = "{username:wangbinghua}"; ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.submit(new Runnable() { @Override public void run() { try { Thread.sleep(1010); } catch (InterruptedException e) { e.printStackTrace(); } //业务处理 System.out.println("业务处理"); stringDeferredResult.setResult(message); } }); //setResult完毕之后,调用该方法 stringDeferredResult.onCompletion(new Runnable() { @Override public void run() { System.out.println("异步调用完成"); //响应完毕之后,将请求从队列中去除掉 deferredResults.remove(stringDeferredResult); } }); stringDeferredResult.onTimeout(new Runnable() { @Override public void run() { System.out.println("业务处理超时"); stringDeferredResult.setResult("error:timeOut"); } }); return stringDeferredResult; } //开启线程定时扫描队列,响应客户端 @Scheduled(fixedRate = 1000) public void scheduleResult(){ System.out.println(new Date()); for(int i = 0;i < deferredResults.size();i++){ DeferredResult<String> deferredResult = deferredResults.getFirst(); deferredResult.setResult("result:" + i); } } }
DeferedResult 两个监听器(onCompletion & onTimeout)
当DeferedResult对象调用setResult之后,响应完毕客户端,则直接调用onCompletion对应的方法。
当业务处理相当耗时,则响应客户端超时,也会调用onCompletion对应的方法以及onTimeout方法。此时,响应客户端的内容为deferedResult.setErrorResult的内容,否则500错误。
发生异常,调用onCompletion方法,此时,响应客户端的内容为deferedResult.setErrorResult的内容,否则500错误。
@RequestMapping("/getResult") @ResponseBody public DeferredResult<String> getDeferredResultController(){ //设置 5秒就会超时 final DeferredResult<String> stringDeferredResult = new DeferredResult<String>(1000); deferredResults.add(stringDeferredResult); final String message = "{username:wangbinghua}"; ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.submit(new Runnable() { @Override public void run() { try { Thread.sleep(1010); } catch (InterruptedException e) { e.printStackTrace(); } //业务处理 System.out.println("业务处理"); stringDeferredResult.setResult(message); } }); //setResult完毕之后,调用该方法 stringDeferredResult.onCompletion(new Runnable() { @Override public void run() { System.out.println("异步调用完成"); deferredResults.remove(stringDeferredResult); } }); stringDeferredResult.onTimeout(new Runnable() { @Override public void run() { System.out.println("业务处理超时"); stringDeferredResult.setResult("error:timeOut"); } }); return stringDeferredResult; }
WebAsyncTask对象使用实例
@RequestMapping("/async") @ResponseBody public WebAsyncTask<String> asyncTask(){ // 1000 为超时设置 WebAsyncTask<String> webAsyncTask = new WebAsyncTask<String>(1000,new Callable<String>(){ @Override public String call() throws Exception { //业务逻辑处理 Thread.sleep(5000); String message = "username:wangbinghua"; return message; } }); webAsyncTask.onCompletion(new Runnable() { @Override public void run() { System.out.println("调用完成"); } }); webAsyncTask.onTimeout(new Callable<String>() { @Override public String call() throws Exception { System.out.println("业务处理超时"); return "<h1>Time Out</h1>"; } }); return webAsyncTask; }
还没有评论,来说两句吧...