springmvc 异步请求

springmvc 异步请求

1、Servlet 规范

为什么需要异步请求?任何技术产生都会有一定的业务场景需求。假设我们有这样的一种业务场景,用户输入某种操作之后,业务逻辑部分会占用大量的时间去处理,这时候如果是同步的处理方式,servlet 线程被阻塞,直到所有的处理完成。如果服务器的请求得到了很多过程,它将达到最大 servlet 线程限制和进一步的请求会拒绝连接错误。servlet 线程应该只是充当 http 协议的搬运工,从接受到用户请求,将数据运送到一个子线程去处理,立即返回继续接受其他请求,当前请求会由子线程处理后返回响应。以下两种时序图分别对应同步和异步的两种方式。

在servlet3.0 规范里面提供了异步的规范。

title: 同步方式
participant 客户端
participant 控制器
participant 逻辑处理

客户端->控制器: 请求响应
控制器->逻辑处理: 逻辑处理
逻辑处理->控制器: 返回处理结果
控制器->客户端: 返回响应
复制代码

title: 异步方式
participant 客户端
participant 控制器
participant 逻辑处理

客户端->控制器: 请求响应
控制器->客户端:释放 servlet 线程 
控制器-->逻辑处理: 逻辑处理
逻辑处理-->控制器: 返回处理结果
控制器-->客户端: 返回响应
note right of 客户端: 子线程返回响应
复制代码

2、springmvc 异步请求

SpringMvc3.2 之后支持异步请求,能够在 controller 中返回一个 Callable 或者 DeferredResult,这样可以提高系统的吞吐量。

  • Callable 的时候,处理流程大致为Spring会启动一个线程去将Callable交给TaskExecutor去处理,然后 DispatcherServlet 退出主线程,同时把 Response 保持打开状态,等到 Callable 处理完成,SpringMvc会重新分配一个Request 请求,DispatcherServlet 重新调用和Callable处理的返回结果值,然后返回视图。

代码示例

    @GetMapping
    public Callable<String> hello() throws Exception {
        Callable<String> helloworld = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "Hello World!";
            }
        };
        return helloworld;
    }
    
复制代码
    //java8 可以这样些
    @GetMapping
    public Callable<String> hello() throws Exception {
        return ( () -> "Hello World!");
    }

复制代码
  • DeferredResult 的时候,执行流程有点区别的是,Callable的时候是由spring去启动的一个线程去执行Callble,而 DeferredResult 的执行线程是由我们(程序员)控制的,只需要将结果set进去即可。

代码示例

//定义执行逻辑的service
class TestService{
    public String exec() {
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        LoggerFactory.getLogger(TestService.class).error("TestService");
        return "HelloWorld";
    }
}

//控制器
@GetMapping
public DeferredResult<String> world() throws Exception{
    logger.error("DeferredResult");
    DeferredResult<String> deferredResult = new DeferredResult<>();
    //异步事件驱动编程模型
    CompletableFuture.supplyAsync(new TestService()::exec).whenCompleteAsync((result, throwable) -> deferredResult.setResult(result));
    return deferredResult;
}


复制代码

总得来说,不论是Callable异或DeferredResult,都是通过释放容器线程,通过另外一个副线程执行逻辑的形式来扩展系统的吞吐能力。

扩展阅读 java多线程的一点资料

转载于:https://juejin.im/post/5b419d22f265da0faa364bf5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值