跨线程获取用户信息

119 阅读1分钟

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 的默认数据存储策略:

image.png