1.java 异步请求
Spring在3.2的版本上就已经为我们提供的相应的机制,以应对Http Nio的场景。
官方文档中说DeferredResult和Callable都是为了异步生成返回值提供基本的支持。
-
*简单来说就是一个请求进来,如果你使用了DeferredResult或者Callable,在没有得到返回数据之前, DispatcherServlet和所有Filter就会退出Servlet容器线程,但响应保持打开状态, 一旦返回数据有了,这个DispatcherServlet就会被再次调用并且处理,以异步产生的方式,向请求端返回值。
2.异步请求实现方式
1. Callable加SpringMvc 自带线程池,可以对SpringBoot 默认创建的ThreadPoolTaskExecutor 进行覆写,按照业务需求定义线程池
/**
* 1.使用 springboot 自动生成的ThreadPoolTaskExecutor 线程池
* @param request
* @param name
* @return
*/
@GetMapping("/test1")
@ResponseBody
public Callable<String> test1(HttpServletRequest request,@RequestParam (required = true) String name){
log.info("--------start-----");
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
log.info("当前线程名" + Thread.currentThread().getName());
return "hello" + name + "访问 test1";
}
};
log.info("--------end-----");
return callable;
}
## 覆写 mvc 线程池
```java
@Configuration
@ConfigurationProperties(prefix = "web-mvc-async")
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(2);
t.setMaxPoolSize(3);
t.setQueueCapacity(1024);
t.setThreadNamePrefix("My-Mvc-Thread-");
t.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //在调用线程,即主线程执行
return t;
}
}
使用自定义线程池和Future 方式
private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(cpuNum, cpuNum * 2, 0L,
TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024));
/**
* 使用配置bean 自定义线程池,返回submit.get() 要放到最后一行,不阻塞主线程
* @param request
*
* */
@GetMapping("/test2")
@ResponseBody
public String test2(HttpServletRequest request,@RequestParam (required = true) String name)
throws ExecutionException, InterruptedException {
log.info("--------start2-----");
Future<String> submit = threadPoolExecutor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
log.info("当前线程名" + Thread.currentThread().getName());
return "hello" + name + "访问 test2";
}
});
log.info("--------end2-----");
return submit.get();
}
对于没有返回值得任务来说可以使用自定义线程池,也可以使用@Async 异步注解