不用session也能随时获取globalUser,用ThreadLocal也太香了

简介: 不用session也能随时获取globalUser,用ThreadLocal也太香了

之前一直不明白,为什么用shiro之类的框架,为什么我们可以在任何地方,只要写上一句


SubjectUtil.getCurrentUser,就可以得到当前的登录用户。按照道理,最初学web的时候,都会被告知有一个叫做session的东西,然后通过request对象就可以得到session,用户登录后,把用户信息存到session里面就可以了。


代码一般是这样:


request.getSession().getAttribute('currentUser');


可是这样就有个麻烦的地方,如果我是在某个service要用到当前用户,就得把request作为参数传进去,很不雅。


而看到shiro这一类的框架我就犯迷糊,我TM似乎也没看到什么地方用session啊,他凭什么可以写一句SubjectUtil.getCurrentUser之类的代码,就搞定了?


后来百度了才知道,原来这类框架都是用ThreadLocal解决这个问题的。


ThreadLocal是java.lang包里面的,所以不用导包直接就可以用,它的作用是在当前线程中开辟一个临时空间,只要是在一个线程中,就可以随取随用。


比如,新建一个MyThreadLocal:


public class MyThreadLocal {
        public static ThreadLocal<User> globalUser = new ThreadLocal<User>();
}


里面维护一个ThreadLocal变量,因为要给其他地方使用,所以设置为static。


什么时候赋值呢?


假设是前后端分离的系统,前端需要送token过来鉴权,那么可以设置一个过滤器或者拦截器,只要请求过来就根据token去redis之类的缓存中获取用户信息,塞到globalUser中,例如:

@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        String token = req.getParameter("token");
        Object user = RedisUtil.get(token);
        if(user != null) {
                MyThreadLocal.globalUser.set((User) user);
        }
        chain.doFilter(req, resp);
}


再搞一个SubjectUtil

public class SubjectUtil {
    public User getCurrentUser() {
        return MyThreadLocal.globalUser.get();
    }
}


于是,一个请求就是一个线程,你在任何地方都可以这样得到用户信息,而无需用到session(因为用session会有很多问题的,现在做项目基本不用session了)

public void userList() {
        User user = new SubjectUtil().getCurrentUser();
        System.out.println(user.getUsername() + "查询了1次用户列表!");
}


最后再来看看ThreadLocal为何能这么牛?

看下他的get方法:

 

  public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }


原来,ThreadLocal内部有个ThreadLocalMap,这是存储所有的线程本地变量的,它不是HashMap,而是ThreadLocal内部的一个静态内部类。但是,它的作用和HashMap差不多。


这个内部Map的key就是每一个当前线程ThreadLocal的地址,这一点可以从set方法中看到

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

 

把当前线程作为key,这也是绝了,不过也正因为如此,才能使得不同线程之间不会相互干扰吧。

本文就分享到这里啦,有问题欢迎斧正。


相关文章
|
6月前
|
存储 安全 Java
面试题:用过ThreadLocal吗?ThreadLocal是在哪个包下的?看过ThreadLocal源码吗?讲一下ThreadLocal的get和put是怎么实现的?
字节面试题:用过ThreadLocal吗?ThreadLocal是在哪个包下的?看过ThreadLocal源码吗?讲一下ThreadLocal的get和put是怎么实现的?
79 0
|
4月前
|
存储 安全 搜索推荐
Cookie和Session的区别,99%的程序员都不知道的细节!
大家好,我是小米,在Web开发中,Cookie和Session是两种重要的状态管理工具。它们有着不同的存储位置、安全性和应用场景。本篇文章将详细解析它们的区别和应用,让你在开发过程中能够更加游刃有余。让我们一起深入了解吧!
103 1
|
5月前
|
存储 安全 Java
《ThreadLocal使用与学习总结:》史上最详细由浅入深解析ThreadLocal
《ThreadLocal使用与学习总结:》史上最详细由浅入深解析ThreadLocal
46 0
|
6月前
|
设计模式 缓存 Java
从ThreadLocal谈到TransmittableThreadLocal,从使用到原理3
从ThreadLocal谈到TransmittableThreadLocal,从使用到原理
882 1
|
6月前
|
存储 前端开发 Java
从ThreadLocal谈到TransmittableThreadLocal,从使用到原理1
从ThreadLocal谈到TransmittableThreadLocal,从使用到原理
1597 0
|
6月前
|
存储 Java
从ThreadLocal谈到TransmittableThreadLocal,从使用到原理2
从ThreadLocal谈到TransmittableThreadLocal,从使用到原理
627 0
|
存储 Java
大厂是怎么用ThreadLocal?ThreadLocal核心原理分析
ThreadLocal**是Java中的一个线程本地变量类。它可以让每个线程都有自己独立的变量副本,而不会相互影响。
119 1
|
Java 数据库连接
ThreadLocal原理和实践
ThreadLocal是线程本地变量,解决多线程环境下成员变量共享存在的问题。ThreadLocal为每个线程创建独立的的变量副本,他的特性是该变量的引用对全局可见,但是其值只对当前线程可用,每个线程都将自己的值保存到这个变量中而各线程不受影响。
162 0
ThreadLocal原理和实践
|
存储 安全 网络协议
还在傻傻分不清cookie和session,cookie与session到底有什么区别?
还在傻傻分不清cookie和session,cookie与session到底有什么区别?
116 0