> 线上用户存储数据后查看提示无权限
不知道什么时候年轻的我曾一度认为Java没啥难度,没有我实现不了的需求,没有我解不了的bug
直到我遇到至今难忘的一个bug 。 线上用户存储数据后查看提示无权限
经过自己的测试后让我更加怀疑人生了,你要么就有问题要么就没问题。一会有一会没有到底又是几个意思呢?偶先的问题真的很难解决啊。问题定位到这里我已经精疲力竭了。然后就放弃了定位
但是问题还是得解决,第二天我又硬着头皮开始研究了。可能第二天头脑比较清醒我发现我们系统中在插入数据的时候会自动获取到当前登录用户并在数据库中记录次数据的创建者及最新的修改者。这更应该说明我们的问题离谱 。但是问题在我们获取当前登录用户的时候出现了问题
对,我将问题追踪了一下,终于将问题本质找到了。我们获取当前登录用户是通过ThreadLocal
来实现的。那么问题就是``ThreadLocal` 获取用户有问题
我们分布式开发系统。我们会在每个模块里添加一个aop拦截器,通过请求头的token再去user模块查询用户基本信息。然后放到``ThreadLocal中。这样我们的系统中随处都可以通过
ThreadLocal` 这个对象获取我们的登陆用户。
别问我为什么要在每个模块都这样做?别问我为什么用ThreadLocal
?别问我为什么是分布式还要这样做? 因为今天我们重点是解决bug
ThreadLocal获取用户信息乱串,导致用户新增数据权限异常
ThreadLocal
是个对象,我们系统中是通过一个工具类获取这个对象的属性的。在这个对象我们提供set、get方法。public static UserInfo getUser() { return userThreadLocal.get(); }
ThreadLocal
对象存储的内容返回出去。这一步应该不会出现问题。 对象中,但是前提是
ThreadLocal`中没有用户。对就是这个问题,如果已经有了用户呢?那么我们真正的用户就会无法添加进去ThreadLocal
对象管理的有问题。导致保存了上次的用户信息从而导致用户信息乱串的现象ThreadLocal
的管理问题,那么我们就好办了。ThreadLocal
将对象保存在线程中。换句话说就是每个线程的数据会相互隔离。基于这个特性我们可以将用户信息存储在这里,这样我们能保证我们的当前线程下执行分各种方法都能通过他获取到用户信息ThreadLocal
内部是将已自己为key, 存储对象为value存储到当前线程中的map中。这个map会随着线程的销毁而被JVM回收。ThreadLocal
中的数据remove。因为他内部是弱引用在下次回收就会将对象回收这样也不会造成内存泄漏的问题ThreadLocal
清空。两种方式都可以完美解决我们的问题/** * 请求生命周期最后一步销毁是做的回调事件 * 用于销毁在线用户信息,防止在线用户信息互相干扰(在多线程复用时) */ @WebListener @Primary public class SysServletRequestListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent requestEvent) { UserInfoUtil.clearUserInfo(); } @Override public void requestInitialized(ServletRequestEvent sre) { } }
ThreadLocal
进行remove。 为什么我推荐这种做法呢。因为请求结束就清空可以快速的让出内存让他去做更加有用的事情。ThreadLocal
后就花了一个小时学习了下他的逻辑并跟踪了他的源码。最后结合我们的业务才发现了眉目ThreadLocal
。我的这次问题也是使用他的典型问题,另外还有一个内存泄漏的问题这是在学习他源码的过程领悟到的一点。关于内存泄漏我们有时间在看吧。问题解决。终于可以继续happy了。