概述
为什么要用异步响应
我们在web接口开发中大部分接口都采用的是同步响应的模式,但是当接口的响应结果需要依赖外部比较耗时的接口时,如果此时再采用同步响应的模式会使servlet线程池的线程无法释放,造成后续的请求无法找到空闲线程处理。
处理耗时接口的几种方式
针对耗时接口的处理一直让servlet线程池中线程阻塞等待结果自然不是一种好的处理方式,为了避免对servlet线程池线程的长时间占用,个人认为有如下几种处理方式:
- 接口拆分:执行接口+执行结果接口,前端先调用执行接口,后端接口接收执行指令后不待指令执行完成即返回,后续前端根据需要选择轮询等方式调用执行结果接口获取执行结果。
- 接口返回DeferredResult:延时结果,一般DeferredResult的结果设置是在我们程序自定义的线程池执行器中设置的,比如A应用需要的结果是B应用设置在redis里的。
- 接口返回Callable:spring自带线程池执行器执行Callable,比如向其他系统接口请求数据的情况就可以采用返回Callable的方式。
代码Demo
- DeferredResult
private ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(1);
@GetMapping("/testDeferredResult")
@ResponseBody
public DeferredResult<String> test1() {
DeferredResult<String> deferredResult = new DeferredResult<>();
scheduledExecutor.schedule(() -> {
deferredResult.setResult("deferred result");
}, 10, TimeUnit.SECONDS);
System.out.println(Thread.currentThread().getName() + "执行结束");
return deferredResult;
}
- Callable
@GetMapping("/testCallable")
@ResponseBody
public Callable<String> test2() {
Callable<String> callable = () -> {
System.out.println("testCallable");
//模拟结果延时返回
Thread.sleep(10000);
return "callable result ttt";
};
System.out.println(Thread.currentThread().getName() + "执行结束");
return callable;
}
Spring异步响应是如何做的
Spring源码对WebAsyncManager的注释:
* The central class for managing asynchronous request processing, mainly intended
* as an SPI and not typically used directly by application classes.
Spring异步请求处理的核心类:WebAsyncManager,其中分别针对controller方法的返回值DeferredResult和Callable有对应的处理方法。
DeferredResult对应处理方法startDeferredResultProcessing,其中的核心代码如下:
deferredResult.setResultHandler(result -> {
result = interceptorChain.applyPostProcess(this.asyncWebRequest, deferredResult, result);
setConcurrentResultAndDispatch(result);
});
具体的处理方法是给deferredResult注册了一个resultHandler,也就是一个回调函数,在我们的应用中其他线程设置deferredResult值时触发这个回调函数,再次将请求给到spring的dispatcherServlet进行处理。
Callable对应的处理方法startCallableProcessing,其中的核心代码如下:
Future<?> future = this.taskExecutor.submit(() -> {
Object result = null;
try {
interceptorChain.applyPreProcess(this.asyncWebRequest, callable);
result = callable.call();
}
catch (Throwable ex) {
result = ex;
}
finally {
result = interceptorChain.applyPostProcess(this.asyncWebRequest, callable, result);
}
setConcurrentResultAndDispatch(result);
});
interceptorChain.setTaskFuture(future);
从代码可以看出,spring的taskExecutor执行了我们controller方法返回的callable对象call方法拿到结果,同样的会再次将结果给到spring的dispatcherServlet进行处理。
最后
以上就是难过奇异果为你收集整理的Spring的延时响应、异步请求处理-DeferredResult和Callable的全部内容,希望文章能够帮你解决Spring的延时响应、异步请求处理-DeferredResult和Callable所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复