60、springmvc-异步请求-返回Callable

@Controller
public class AsyncController {

    @RequestMapping("async01")
    @ResponseBody
    public Callable<String> async01() {

        System.out.println("主线程开始..." + Thread.currentThread() + "===》" + System.currentTimeMillis());
        Callable<String> callable = new Callable<String>() {
            public String call() throws Exception {
                System.out.println("子线程开始..." + Thread.currentThread() + "===》" + System.currentTimeMillis());
                Thread.sleep(3000);
                System.out.println("子线程结束..." + Thread.currentThread() + "===》" + System.currentTimeMillis());
                return "Callable<String> async01()";
            }
        };
        System.out.println("主线程结束..." + Thread.currentThread() + "===》" + System.currentTimeMillis());
        return callable;
    }
}

60.1 Spring MVC异步执行

  1. 控制器返回Callable
  2. Spring异步处理,将Callable 提交到 TaskExecutor 使用一个隔离的线程进行执行
  3. DispatcherServlet和所有的Filter退出web容器的线程,但是response 保持打开状态;
  4. Callable返回结果,SpringMVC将请求重新派发给容器,恢复之前的处理;
  5. 根据Callable返回的结果。SpringMVC继续进行视图渲染流程等(从收请求-视图渲染)。

60.2 运行结果

60.3 异步拦截器

  1. 原生API的AsyncListener
  2. SpringMVC:实现AsyncHandlerInterceptor

60.4 注意警告。

  • 查看执行类源码 org.springframework.web.context.request.async.WebAsyncManager 有这么一段获取
  • 如果没有指定 AsyncTaskExecutor 就会 warning 警告 logExecutorWarning();
AsyncTaskExecutor executor = webAsyncTask.getExecutor();
if (executor != null) {
	this.taskExecutor = executor;
}
else {
	logExecutorWarning();
}

  • 解决:我们可以自己配置一个线程池来执行,如下
  • 通过在AppConfig implements WebMvcConfigurerconfigurer.setTaskExecutor(threadPoolTaskExecutor());来执行
/**
 * 自定义 异步任务执行线程池,解决warnning警告
 * @return
 */
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.initialize();
    executor.setCorePoolSize(10);
    executor.setMaxPoolSize(50);
    executor.setThreadNamePrefix("JHW");
    return executor;
}

@Bean
public TimeoutCallableProcessingInterceptor timeoutCallableProcessingInterceptor() {
    return new TimeoutCallableProcessingInterceptor();
}

public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    configurer.setTaskExecutor(threadPoolTaskExecutor());
    configurer.setDefaultTimeout(60 * 1000L);
    configurer.registerCallableInterceptors(timeoutCallableProcessingInterceptor());
}