ThreadLocal保存用户信息

1.介绍

在并发请求情况下,因为每次请求都有不同的用户信息,我们必须保证每次请求保存的用户信息互不干扰,线程独立。注意:这里不是解决多线程资源共享问题,而是要保证每个线程都有自己的用户资源,互不干扰

ThreadLocal的作用主要是做数据隔离,填充的数据只属于当前线程,变量的数据对别的线程而言是相对隔离的,在多线程环境下,如何防止自己的变量被其它线程篡改。

而JDK中提供的ThreadLocal恰好满足这个需求,那么ThreadLocal是如何实现这一需求的呢?

ThreadLocal保存用户信息_第1张图片

关键点:

  • 每个线程(Thread)内部都持有一个ThreadLocalMap对象。
  • ThreadLocalMap的Key是某个ThreadLocal对象,值是任意Object。
  • 不同线程,内部有自己的ThreadLocalMap,因此Map中的资源互相不会干扰。

数据在堆栈中的存储示意图:

ThreadLocal保存用户信息_第2张图片

2.基本使用

public class UserHolder {
    private static final ThreadLocal TL = new ThreadLocal<>();

    public static void setUserId(Long userId) {
        TL.set(userId);
    }

    public static Long getUserId() {
        return TL.get();
    }

    public static void removeUserId() {
        TL.remove();
    }
}

3. 工具类

import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


 /**
 * @author 暗余
 * @date 2021/7/17 15:44
 */
@SuppressWarnings("unused")
public final class ThreadLocalUtils {

    private static final ThreadLocal> THREAD_LOCAL =
            ThreadLocal.withInitial(() -> new ConcurrentHashMap<>(16));

    /**
     * 获取到ThreadLocal中值
     *
     * @return ThreadLocal存储的是Map
     */
    public static Map getThreadLocal() {
        return THREAD_LOCAL.get();
    }

    /**
     * 从ThreadLocal中的Map获取值
     *
     * @param key Map中的key
     * @param  Map中的value的类型
     * @return Map中的value值 可能为空
     */
    public static  T get(String key) {
        return get(key, null);
    }

    /**
     * 从ThreadLocal中的Map获取值
     *
     * @param key          Map中的key
     * @param defaultValue Map中的value的为null 是 的默认值
     * @param           Map中的value的类型
     * @return Map中的value值 可能为空
     */
    @SuppressWarnings("unchecked")
    public static  T get(String key, T defaultValue) {
        Map map = THREAD_LOCAL.get();
        if (MapUtils.isEmpty(map)) {
            return null;
        }
        return (T) Optional.ofNullable(map.get(key)).orElse(defaultValue);
    }

    /**
     * ThreadLocal中的Map设置值
     *
     * @param key   Map中的key
     * @param value Map中的value
     */
    public static void set(String key, Object value) {
        Map map = THREAD_LOCAL.get();
        map.put(key, value);
    }

    /**
     * ThreadLocal中的Map 添加Map
     *
     * @param keyValueMap 参数map
     */
    public static void set(Map keyValueMap) {
        Map map = THREAD_LOCAL.get();
        map.putAll(keyValueMap);
    }

    /**
     * 删除ThreadLocal中的Map 中的value
     *
     * @param key Map中的key
     */
    public static void delete(String key) {
        Map map = THREAD_LOCAL.get();
        if (MapUtils.isEmpty(map)) {
            return;
        }
        map.remove(key);
    }

    /**
     * 删除ThreadLocal中的Map
     */
    public static void remove() {
        THREAD_LOCAL.remove();
    }

    /**
     * 从ThreadLocal中的Map获取值 根据可key的前缀
     *
     * @param prefix key 的前缀
     * @param     Map中的value的类型
     * @return 符合条件的Map
     */
    @SuppressWarnings("unchecked")
    public static  Map fetchVarsByPrefix(String prefix) {
        Map vars = new HashMap<>(16);
        if (StringUtils.isBlank(prefix)) {
            return vars;
        }
        Map map = THREAD_LOCAL.get();
        if (MapUtils.isEmpty(map)) {
            return vars;
        }
        return map.entrySet().stream().filter(test -> test.getKey().startsWith(prefix))
                .collect(Collectors.toMap(Map.Entry::getKey, time -> (T) time.getValue()));
    }

    /**
     * 删除ThreadLocal中的Map 中的Value  按 Map中的Key的前缀
     *
     * @param prefix Map中的Key的前缀
     */
    public static void deleteVarsByPrefix(String prefix) {
        if (StringUtils.isBlank(prefix)) {
            return;
        }
        Map map = THREAD_LOCAL.get();
        if (MapUtils.isEmpty(map)) {
            return;
        }
        map.keySet().stream().filter(o -> o.startsWith(prefix)).collect(Collectors.toSet()).forEach(map::remove);
    }
}

4. 例子

package net.facelib.eam.plancenter.webController.config;

import com.alibaba.fastjson.JSONObject;
import net.facelib.eam.*;
import net.facelib.eam.plancenter.common.MyPlanConstant;
import net.facelib.eam.plancenter.common.PlanException;
import net.facelib.eam.plancenter.webController.utils.ServletUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * @author lc
 * @version 1.0
 * @date 2022/7/5 9:23
 */
@Aspect
@Component
@Order(1)
public class PermissionAspect {
    private static Logger logger = LoggerFactory.getLogger(PermissionAspect.class);
    private static ThreadLocal> userInfo = new ThreadLocal<>();

    @Autowired
    protected ITokenAccessor tokenAccessor;

    @Pointcut("execution(* net.facelib.eam.plancenter.webController.service..*.*(..))")
    public void pointCut(){
    }

    @Before("pointCut()")
    public void before(JoinPoint joinPoint){
        try {
            String tokenid = ServletUtils.getRequest().getHeader("tokenid");
            Token token = tokenAccessor.getToken(tokenid);
            Map map = new HashMap<>();
            map.put("userId", token.getId());
            map.put("userName", token.getName());
            map.put("props", token.getProps());
            map.put("tokenid", tokenid);
            userInfo.set(map);
        } catch (Exception e){
            logger.error("token解析失败"+ e);
            throw new PlanException(EamErrorType.EAM_INVALID_TOKEN.getValue(), MyPlanConstant.PC_USER_TOKEN_ERROR, e);
        }
    }

    public static Long getUserId() {
        Map map = userInfo.get();
        Long userId = Long.valueOf(map.get("userId").toString());
        return userId;
    }

    public static String getUserName() {
        Map map = userInfo.get();
        return map.get("nickName").toString();
    }

    public static JSONObject getProps() {
        Map map = userInfo.get();
        JSONObject jsonObject = JSONObject.parseObject(map.get("props").toString());
        return jsonObject;
    }

    public static String getTokeid() {
        Map map = userInfo.get();
        String tokenid = map.get("tokenid").toString();
        return tokenid;
    }
}

你可能感兴趣的:(Java,JUC,工具类,java,开发语言,后端)