Spring Security 中想要获取登录用户信息,不能在子线程中获取,只能在当前线程中获取,其中一个重要的原因就是 SecurityContextHolder 默认将用户信息保存在 ThreadLocal 中。
public class SecurityContextHolder {
public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";
public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";
public static final String MODE_GLOBAL = "MODE_GLOBAL";
...
...
}
第二种存储策略 MODE_INHERITABLETHREADLOCAL 就支持在子线程中获取当前登录用户信息,而 MODE_INHERITABLETHREADLOCAL 的底层使用的就是 InheritableThreadLocal。
@Test
void contextLoads() {
ThreadLocal threadLocal = new ThreadLocal();
threadLocal.set("javaboy");
System.out.println("threadLocal.get() = " + threadLocal.get());
new Thread(new Runnable() {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("name+threadLocal.get() = " + name + ":" + threadLocal.get());
}
}).start();
}
$:threadLocal.get() = javaboy
$:name+threadLocal.get() = Thread-121:null
@Test
void contextLoads() {
ThreadLocal threadLocal = new InheritableThreadLocal();
threadLocal.set("javaboy");
System.out.println("threadLocal.get() = " + threadLocal.get());
new Thread(new Runnable() {
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println("name+threadLocal.get() = " + name + ":" + threadLocal.get());
}
}).start();
}
$:threadLocal.get() = javaboy
$:name+threadLocal.get() = Thread-121:javaboy
SecurityContextHolder 中通过 System.getProperty 来获取默认的数据存储策略,所以我们可以在项目启动时通过修改系统变量进而修改 SecurityContextHolder 的默认数据存储策略: