java new ThreadLocal 储存一个请求上下文的数据 供请求用的代码使用,但不成功?

作者站长头像
站长
· 阅读数 10

1、封装的BaseContext工具类

package com.quanneng.xc_mall.common;

import com.quanneng.xc_mall.entity.Config;

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

public class BaseContext {
    
    private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = new ThreadLocal<>();
    
    
    public static Map<String, Object> getLocalMap() {
        Map<String, Object> map = THREAD_LOCAL.get();
        if (map == null) {
            map = new HashMap<>(10);
            THREAD_LOCAL.set(map);
        }
        return map;
    }
    
    public static void setLocalMap(Map<String, Object> threadLocalMap) {
        THREAD_LOCAL.set(threadLocalMap);
    }
    
    
    public static void set(String key, Object value) {
        Map<String, Object> map = getLocalMap();
        map.put(key, value);
    }
    
    
    public static Object get(String key) {
        Map<String, Object> map = getLocalMap();
        return map.getOrDefault(key, "");
    }
    
    
    public static Config getConfig() {
        Map<String, Object> map = getLocalMap();
        return (Config) map.getOrDefault("config", null);
    }
    
    public static void setConfig(Config value) {
        Map<String, Object> map = getLocalMap();
        map.put("config", value);
    }
    
}

2、拦截器缓存db.config到redis数据

package com.quanneng.xc_mall.interceptor;


import com.quanneng.xc_mall.common.BaseContext;
import com.quanneng.xc_mall.config.redis.JedisPoolUtilConfig;
import com.quanneng.xc_mall.entity.Config;
import com.quanneng.xc_mall.service.ConfigService;
import com.quanneng.xc_mall.utils.JedisPoolUtil;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

public class WriteRedisCacheInterceptor implements HandlerInterceptor {
    
    @Resource
    private JedisPoolUtilConfig jedisPoolUtilConfig;
    
    @Resource
    private JedisPoolUtil jedisPoolUtil;
    
    @Resource
    private ConfigService configService;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 1.获取前端
        JedisPoolUtil redisUtil = jedisPoolUtil.setRedisTemplate(jedisPoolUtilConfig.getRedisTemplateByDb(10));
        
        // 2.判断是否存在
        Object config = redisUtil.get("config");
        // 存在:直接赋值:
        if (config != null && !Objects.equals(config, "")) {
            BaseContext.setConfig((Config) config);
            return true;
        }
        // 不存在:新建
        // 3.查询db
        Config byId = configService.getById(1);
        if (byId == null) {
            throw new RuntimeException("网站参数不存在,请联系网站人员");
        }
        
        // 储存:redis
        redisUtil.set("config", byId, 60);
        
        // 4.全局储存
        BaseContext.setConfig(byId);
        
        return true;
    }
    
}

3、请求中,用到的任意文件中使用

Config   config   = BaseContext.getConfig();

4、请求结束后,管理人员修改了config字段的值,但是请求中获取到的值没变。

这是什么原因呢?还有,用new ThreadLocal<>()储存不同用户的请求 的用户信息,他们用户信息会串吗,安全吗?

private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = new ThreadLocal<>();

5、我这段代码有问题吗?我这个是属于请求上下文吗,跟程序上下文不同,是每一个请求隔离吗?

6、开发时,只有将程序停止掉,再重启,就会更新config的值,除此之外不会更新,并且redis中过期的config还存在。

回复
1个回答
avatar
test
2024-07-15
  1. 建议加日志,确认代码执行情况
  2. 默认情况下,一个请求运行在一个线程,所以可以使用ThreadLocal保存数据
  3. 接上条,建议在拦截器里做一个清空ThreadLocal的处理,避免某些奇怪的bug
回复
likes
适合作为回答的
  • 经过验证的有效解决办法
  • 自己的经验指引,对解决问题有帮助
  • 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
  • 询问内容细节或回复楼层
  • 与题目无关的内容
  • “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容