Spring Boot uses WebAsyncTask to return results asynchronously
- 2021-01-22 05:11:48
- OfStack
In Spring Boot (Spring MVC), requests are synchronous by default, and one thread is responsible for each request from the beginning to the end. In many cases, in order to improve the throughput, some operations need to be asynchronous. In addition to some time-consuming business logic, our query interface can also be asynchronous.
A request to the service is received by a thread using the web container, such as thread http-nio-8084-exec-1
We can use WebAsyncTask to distribute this request to a new thread to execute, http-nio-8084-exec-1 to receive processing of other requests. Once WebAsyncTask returns the data, it is called again and processed, asynchronously, to return the value to the requester.
The sample code is as follows:
@RequestMapping(value="/login", method = RequestMethod.GET)
public WebAsyncTask<ModelAndView> longTimeTask(){
System.out.println("/login Is called thread id is : " + Thread.currentThread().getName());
Callable<ModelAndView> callable = new Callable<ModelAndView>() {
public ModelAndView call() throws Exception {
Thread.sleep(1000); / Simulate long - duration tasks
ModelAndView mav = new ModelAndView("login/index");
System.out.println(" Execute successfully thread id is : " + Thread.currentThread().getName());
return mav;
}
};
return new WebAsyncTask<ModelAndView>(callable);
}
You can see the output as follows:
/login is called thread id is: http-nio-8084-exec-1
thread id: MvcAsync1 successfully executed
The thread that precedes the execution of the business logic is not the same as the thread that specifically processes the business logic, which serves our purpose.
Then I did a concurrency test and found that I was constantly creating the ES43en1 thread, and I thought, isn't there a thread pool?
By reading the source code found that is true, WebAsyncManager is Spring MVC management async processing central class.
The default is to use ES53en, which creates 1 new thread per request
private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(this.getClass().getSimpleName());
If the task specifies executor, the task specifies SimpleAsyncTaskExecutor. If not, the default SimpleAsyncTaskExecutor
AsyncTaskExecutor executor = webAsyncTask.getExecutor();
if (executor != null) {
this.taskExecutor = executor;
}
We can configure the thread pool for async without having to specify it separately for each task
Through configurer. setTaskExecutor (threadPoolTaskExecutor ()); To specify the
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.context.request.async.TimeoutCallableProcessingInterceptor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(60 * 1000L);
configurer.registerCallableInterceptors(timeoutInterceptor());
configurer.setTaskExecutor(threadPoolTaskExecutor());
}
@Bean
public TimeoutCallableProcessingInterceptor timeoutInterceptor() {
return new TimeoutCallableProcessingInterceptor();
}
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor t = new ThreadPoolTaskExecutor();
t.setCorePoolSize(10);
t.setMaxPoolSize(50);
t.setThreadNamePrefix("YJH");
return t;
}
}
After the configuration, you can see that the output thread name starts with YJH, and it does not create a new thread
You can see the output as follows:
/login Is called thread id is : http-nio-8084-exec-1
Execute successfully thread id is : YJH1
conclusion