一、首先配置好的@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(); }