如何进行SpringMVC异步编程
前言
SpringMVC是我们平时用的最多的异步编程框架,但是我们在使用的时候基本上只是用到了它的同步编程。一般情况下是够用的,但是在并发量比较大的时候可能就不会够用了,因为一个请求会占用一个tomcat线程,这个时候我们可以尝试使用异步编程的方式来提高吞吐量。
环境准备
maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
同步
我们在介绍异步编程之前先回顾一下同步的方式
项目结构:
controller
service
我这里只是做一下模拟操作,就不引用数据库的操作了。
这种同步的编程方式可能就是我们平时用的最多的一种形式,简单直观。
异步
首先我们需要在启动类上加上 @EnableAsync
注解开启异步支持,然后我们再定义一个Executor
,这样的话我们在想要异步执行的方法上面加上@Async("asyncExecutor")
注解。如果觉得每次都要指定使用哪个线程池麻烦的话,可以让我们的配置类继承AsyncConfigurerSupport
然后覆写getAsyncExecutor()
方法,这样我们就可以直接使用@Async
而不用指定名称。
service改造
我们service返回一个AsyncResult
或者 CompletableFuture
,然后在方法上面加上@Async注解
虽然我们的service改造成了异步的但是如果我们在controller直接调用get方法获取值那么还是会阻塞住
controller改造
controller的异步有多种方式我这里介绍常用的三种
- DeferredResult
DeferredResult 这个类代表延迟结果。DeferredResult 可以用在异步任务中,其他线程能够获取 DeferredResult 并设置 DeferredResult 的返回数据。通常可以使用线程池、队列等配合。我们这里直接使用之前定义的哪个线程池。
- Callable
使用 Callable 进行异步处理与 DeferredResult 类似。不同的是,Callable 会交给系统指定的 TaskExecutor 执行。
- WebAsyncTask
后两个默认是使用SimpleAsyncTaskExecutor,这个会为每次请求创建一个新的线程。
我们可以配置async 的线程池,不需要为每个任务单独指定。
通过configurer.setTaskExecutor(threadPoolTaskExecutor());来指定线程池。
这样就可以指定TaskExecutor了