ThreadLocal存储用户登录信息

一,问题提出:

通常在项目设计开发中,用户登录后,我们会将用户的信息存到session,如果想在其它地方获取session中的用户信息,我们需要先获取HttpServletRequest,再通过request.getSession得到HttpSession。例如下代码:

public static User getSessionUser(HttpServletRequest request)
    {
        if(request.getSession().getAttribute( "sessionuser" ) != null)
        {
            return (User)request.getSession().getAttribute( "sessionuser" );
        }
        return null;
    }

但是这样操作会很麻烦并且存在并发问题

1.1 每次获取session中的用户信息,先手动获取到HttpServletRequest对象。

每次要获取session都要传递Request请求参数,尤其是service层或者dao层也要使用到user的信息,而通常在一个大型项目中,service层和dao层都是和web层分离开来,

都是单独的工程,不依赖servlet api,大家也不会为了在service层或者dao层获取登录用户信息而这么做,这样显得会很奇怪,所以我们只能在action中调用service的时候,将用户信息以参数形式传过去。

对于session中的用户信息,我们不仅想要在action中随用随取,还想在其它普通类中取,即使不依赖servlet api, 我们也要在方法里随用随取,我们在处理请求的时候,很多操作都要获取当前用户的ID等信息,由上可见,我们凡是在action的方法中任何一处想要获取session中的用户信息,则必须要先手动获取到HttpServletRequest,是不是比较麻烦

1.2 如果遇到高并发,多人同时登录系统时,会出现session混乱。

考虑到并发,如果两个人或者多人同时登录系统,A置成自己的session了,B又置成他的session了,两人开始打架了。

二,解决方案

客户端发送的每次http请求,对应的服务端都会分配一个新的线程来处理,在处理过程中涉及到下面类中的方法都属于相同的一个线程。

我们引入ThreadLocal,首先它不是用来解决多线程并发共享一类问题的,它解决的是在一个线程中参数的传递。

2.1 ThreadLocal

顾名思义,就是本地线程,可是这个名字实在容易让人误解,因为其实它是本地线程局部变量的意思,首先我们要知道,我们每个请求都会对应一个线程,

这个ThreadLocal就是这个线程使用过程中的一个变量,该变量为其所属线程所有,各个线程互不影响。

这里我们要了解一下ThreadLocal的三个方法:

ThreadLocal.set(T value); //设置值
ThreadLocal.get(); //获取值
ThreadLocal.remove(); //移除值

具体实例:

package com.tigerhhzz.wuaimai.common;
/**
 * 基于ThreadLocal封装工具类,用户保存和获取当前登录用户id
 */
public class BaseContext {
    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
    /**
     * 设置值
     * @param id
     */
    public static void setCurrentId(Long id){
        threadLocal.set(id);
    }
    /**
     * 获取值
     * @return
     */
    public static Long getCurrentId(){
        return threadLocal.get();
    }
}

所以我们可以借助这个ThreadLocal来存储登录用户的信息,在一个请求中,所有调用的方法都在同一个线程中去处理,这样就实现了在任何地方都可以获取到用户信息了,从而摆脱了HttpServletRequest的束缚。

2.2 避免了跨层之间的参数传递,实现了层与层之间的松耦合。

ThreadLocal并不是一个Thread,而是Thread的局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立的改变自己的副本,而不会影响其他线程所对应的副本。

ThreadLocal为每个线程提供了单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。

后续直接在你的登录方法中调用这个类然后把用户信息通过setCurrentId或者getCurrentId进行添加或者调用就行,当然你也可以修改这个方法。

  • 32
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ThreadLocal是一种线程局部变量,可以在每个线程存储和访问数据,而不会被其他线程访问到。在多线程环境下,可以使用ThreadLocal存储用户信息,以便在后续的代码中直接获取用户信息。 具体实现原理如下: 1. 在UserContext类中定义了一个静态的ThreadLocal变量,用于存储用户信息\[2\]。 2. 当用户登录成功后,将用户信息存储ThreadLocal中,通过调用setBaseUser方法\[2\]。 3. 在后续的代码中,可以通过调用getUser方法来获取当前线程存储用户信息\[2\]。 4. 当用户请求处理完成后,可以通过调用remove方法来清除当前线程存储用户信息,以防止内存泄漏\[2\]。 使用ThreadLocal存储用户信息的好处是可以避免在代码中一层一层传递HttpServletRequest或其他对象来获取用户信息\[3\]。每个线程都有自己独立的ThreadLocal变量,可以在当前线程中直接获取用户信息,提高了代码的简洁性和可读性。 需要注意的是,由于ThreadLocal的特性,需要在适当的时候调用remove方法来清除ThreadLocal中的数据,以防止内存泄漏\[1\]。在登录拦截中,可以在controller执行完成后的afterCompletion方法中调用remove方法来清除用户信息\[1\]。 总结起来,ThreadLocal可以用于存储用户信息,通过在每个线程存储和获取数据,避免了在代码中一层一层传递对象的繁琐操作,提高了代码的简洁性和可读性。同时,需要注意在适当的时候调用remove方法来清除ThreadLocal中的数据,以防止内存泄漏。 #### 引用[.reference_title] - *1* [ThreadLocal存储用户登录信息](https://blog.csdn.net/weixin_46000937/article/details/126828778)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v4^insert_chatgpt"}} ] [.reference_item] - *2* *3* [spring boot项目使用threadlocal存储用户信息实现数据权限控制](https://blog.csdn.net/bird_tp/article/details/117297856)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v4^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

银氨溶液

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值