最近工作中有需求做excel异步导出功能,发现在使用@Async后,子线程中获取不到request中的参数信息,故对此问题进行记录
@Ascyn基本配置(旧)
@Configuration
@EnableAsync
@Slf4j
public class AsyncConfig {
@Value("${async.executor.thread.core_pool_size:10}")
private int corePoolSize;
@Value("${async.executor.thread.max_pool_size:20}")
private int maxPoolSize;
@Value("${async.executor.thread.queue_capacity:2000}")
private int queueCapacity;
@Value("${async.executor.thread.name.prefix:async-job}")
private String namePrefix;
@Bean(name = "jobExecutor")
public Executor asyncServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
executor.setQueueCapacity(queueCapacity);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
@Ascyn基本配置(新)
原来的配置需要进行优化,添加: executor.setTaskDecorator(new SubThreadTaskDecorator());
@Configuration
@EnableAsync
@Slf4j
public class AsyncConfig {
@Value("${async.executor.thread.core_pool_size:10}")
private int corePoolSize;
@Value("${async.executor.thread.max_pool_size:20}")
private int maxPoolSize;
@Value("${async.executor.thread.queue_capacity:2000}")
private int queueCapacity;
@Value("${async.executor.thread.name.prefix:async-job}")
private String namePrefix;
@Bean(name = "jobExecutor")
public Executor asyncServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
executor.setQueueCapacity(queueCapacity);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix(namePrefix);
// ===== 自己实现TaskDecorator =====
executor.setTaskDecorator(new SubThreadTaskDecorator());
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
SubThreadTaskDecorator.java
主要的逻辑在于request.startAsync()
public class SubThreadTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
AsyncContext asyncContext = null;
if (attributes!=null) {
HttpServletRequest request = attributes.getRequest();
// 开启异步
asyncContext = request.startAsync();
// 设置超时时间
asyncContext.setTimeout(999999);
}
AsyncContext finalAsyncContext = asyncContext;
return () -> {
try {
RequestContextHolder.setRequestAttributes(attributes,true);
runnable.run();
} finally {
RequestContextHolder.resetRequestAttributes();
if (finalAsyncContext !=null) {
finalAsyncContext.complete();
}
}
};
}
}
注意:servlet默认的异步处理时间为10秒,如果你的子线程执行时间会超过10秒的话,记得设置asyncContext.setTimeout(999999),否则会报: The request associated with the AsyncContext has already completed processing.