一 、问题
某个功能因涉及的表比较多,想改成多线程异步操作。
但是在功能实现过程中,问题出来了
在登入完成后项目在请求中封装了HospitalId在请求域中,然后继承项目封装好的BaseService可以在Service层直接调用this.getHospitalId()获取值
当开启多线程的时候this.getHospitalId()会报错 空指针异常
正常操作是
//开启线程前获取请求
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//每一个线程都来共享之前的请求数据
RequestContextHolder.setRequestAttributes(requestAttributes);
但这样还是会空指针
二、解决方法
使用了Spring Security获取的请求就变了
//在主线程中获取安全上下文
SecurityContext securityContext = SecurityContextHolder.getContext();
//将主线程中的安全上下文设置到子线程中的ThreadLocal中
SecurityContextHolder.setContext(securityContext);
// 清除操作
// 将调用者中的安全上下文设置到当前业务子线程中的ThreadLocal中。
SecurityContextHolder.clearContext();
第三步的清除操作必不可少,不然会导致异步线程的安全上下文传播到线程池中,而如果该线程为线程池的核心线程,下次该线程执行时又没有设置安全上下文,则会获取到错误的信息(也就是这次设置的安全上下文信息)
三、原因
因为Spring Security的安全上下文默认是存储在ThreadLocal(也就是线程本地)的,启动其他线程执行的时候,就会丢失掉上下文信息。