之前一直不明白,为什么用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,这也是绝了,不过也正因为如此,才能使得不同线程之间不会相互干扰吧。
本文就分享到这里啦,有问题欢迎斧正。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)