• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

SpringBoot异步处理的四种实现方式

springboot 搞代码 4年前 (2022-01-09) 42次浏览 已收录 0个评论

本篇文章我们以SpringBoot中异步的使用(包括:异步调用和异步方法两个维度)来进行讲解。

异步请求与同步请求

我们先通过一张图来区分一下异步请求和同步请求的区别:

在上图中有三个角色:客户端、Web容器和业务处理线程。

两个流程中客户端对Web容器的请求,都是同步的。因为它们在请求客户端时都处于阻塞等待状态,并没有进行异步处理。

在Web容器部分,第一个流程采用同步请求,第二个流程采用异步回调的形式。

通过异步处理,可以先释放容器分配给请求的线程与相关资源,减轻系统负担,从而增加了服务器对客户端请求的吞吐量。但并发请求量较大时,通常会通过负载均衡的方案来解决,而不是异步。

Servlet3.0中的异步

Servlet 3.0之前,Servlet采用Thread-Per-Request的方式处理请求,即每一次Http请求都由一个线程从头到尾处理。当涉及到耗时操作时,性能问题便比较明显。

Servlet 3.0中提供了异步处理请求。可以先释放容器分配给请求的线程与相关资源,减轻系统负担,从而增加服务的吞吐量。

Servlet 3.0的异步是通过AsyncContext对象来完成的,它可以从当前线程传给另一个线程,并归还初始线程。新的线程处理完业务可以直接返回结果给客户端。

AsyncContext对象可以从HttpServletRequest中获取:

@RequestMapping("/async")
public void async(HttpServletRequest request) {
    AsyncContext asyncContext = request.getAsyncContext();
}

在AsyncContext中提供了获取ServletRequest、ServletResponse和添加监听(addListener)等功能:

public interface AsyncContext {

    ServletRequest getRequest();

    ServletResponse getResponse();

    void addListener(AsyncListener var1);

    void setTimeout(long var1);

    // 省略其他方法
}

不仅可以通过AsyncContext获取Request和Response等信息,还可以设置异步处理超时时间。通常,超时时间(单位毫秒)是需要设置的,不然无限等下去不就与同步处理一样了。

通过AsyncContext的addListener还可以添加监听事件,用来处理异步线程的开始、完成、异常、超时等事件回调。

addListener方法的参数AsyncListener的源码如下:

public interface AsyncListener extends EventListener {
    // 异步执行完毕时调用
    void onComplete(AsyncEvent var1) throws IOException;
    // 异步线程执行超时调用
    void onTimeout(AsyncEvent var1) throws IOException;
    // 异步线程出错时调用
    void one rror(AsyncEvent var1) throws IOException;
    // 异步线程开始时调用
    void onStartAsync(AsyncEvent var1) throws IOException;
}

通常,异常或超时时返回调用方错误信息,而异常时会处理一些清理和关闭操作或记录异常日志等。

基于Servlet方式实现异步请求

下面直接看一个基于S本文来源gaodaimacom搞#^代%!码&网*ervlet方式的异步请求示例:

@GetMapping(value = "/email/send")
public void servletReq(HttpServletRequest request) {
    AsyncContext asyncContext = request.startAsync();
    // 设置监听器:可设置其开始、完成、异常、超时等事件的回调处理
    asyncContext.addListener(new AsyncListener() {
        @Override
        public void onTimeout(AsyncEvent event) {
            System.out.println("处理超时了...");
        }

        @Override
        public void onStartAsync(AsyncEvent event) {
            System.out.println("线程开始执行");
        }

        @Override
        public void one rror(AsyncEvent event) {
            System.out.println("执行过程中发生错误:" + event.getThrowable().getMessage());
        }

        @Override
        public void onComplete(AsyncEvent event) {
            System.out.println("执行完成,释放资源");
        }
    });
    //设置超时时间
    asyncContext.setTimeout(6000);
    asyncContext.start(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(5000);
                System.out.println("内部线程:" + Thread.currentThread().getName());
                asyncContext.getResponse().getWriter().println("async processing");
            } catch (Exception e) {
                System.out.println("异步处理发生异常:" + e.getMessage());
            }
            // 异步请求完成通知,整个请求完成
            asyncContext.complete();
        }
    });
    //此时request的线程连接已经释放了
    System.out.println("主线程:" + Thread.currentThread().getName());
}

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:SpringBoot异步处理的四种实现方式

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址