一、首先配置好的@Async線程池配置類
@EnableAsync
@Configuration
public class AsyncTaskConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(1);// 最小線程數 taskExecutor.setMaxPoolSize(10);// 最大線程數 taskExecutor.setQueueCapacity(25);// 等待隊列 taskExecutor.setWaitForTasksToCompleteOnShutdown(true);// 等待所有任務結束后再關閉線程池 taskExecutor.initialize(); return taskExecutor; } }
在注解@Async中調用的方法中如果使用security來獲取用戶信息應該是獲取不到的,原因是異步任務開啟了新線程,所以用的登錄信息不能在子線程獲取,只能在主線程獲取,因為securityContextHolder默認將用戶信息保存在了ThreadLocal
主線程Security信息,即調用異步方法之前線程:
子線程security信息,即調用異步方法之后信息,可以看到getUserInfo為null,什么也沒獲取到,並且當前線程名如果在線程池配置 的話也會顯示自定義命名
比如在開始的AsyncTaskConfig配置文件中在配置線程池時加入前綴:
executor.setThreadNamePrefix("-TaskExecutor-");
在上面可以通過debug看到線程的用戶信息為null,所以需要我們手動往里傳入主線程的信息:
解決辦法:新建公共方法,在調用異步方法之前獲取到userInfo,將userInfo作為參數輸出如異步方法中,異步方法中調用setUserInfo方法
private static final ThreadLocal<UserInfo> context = new ThreadLocal<UserInfo>(); public void setUserInfo(){ UserInfo currentThreadUserInfo = SecurityHelper.getUserInfo(); context.set(currentThreadUserInfo); }
在使用完之后,調用clearUserInfo清空信息:
private static final ThreadLocal<UserInfo> context = new ThreadLocal<UserInfo>(); public void setUserInfo(){ UserInfo currentThreadUserInfo = SecurityHelper.getUserInfo(); context.set(currentThreadUserInfo); } public void clearUserInfo(){ context.remove(); }