我是靠谱客的博主 难过奇异果,最近开发中收集的这篇文章主要介绍Spring的延时响应、异步请求处理-DeferredResult和Callable,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

为什么要用异步响应

        我们在web接口开发中大部分接口都采用的是同步响应的模式,但是当接口的响应结果需要依赖外部比较耗时的接口时,如果此时再采用同步响应的模式会使servlet线程池的线程无法释放,造成后续的请求无法找到空闲线程处理。

处理耗时接口的几种方式

针对耗时接口的处理一直让servlet线程池中线程阻塞等待结果自然不是一种好的处理方式,为了避免对servlet线程池线程的长时间占用,个人认为有如下几种处理方式:

  1. 接口拆分:执行接口+执行结果接口,前端先调用执行接口,后端接口接收执行指令后不待指令执行完成即返回,后续前端根据需要选择轮询等方式调用执行结果接口获取执行结果。
  2. 接口返回DeferredResult:延时结果,一般DeferredResult的结果设置是在我们程序自定义的线程池执行器中设置的,比如A应用需要的结果是B应用设置在redis里的。
  3. 接口返回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所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(37)

评论列表共有 0 条评论

立即
投稿
返回
顶部