基于拦截器对 ThreadLocal 的使用通常在一些需要处理与当前线程相关的数据的场景中非常有用。 ThreadLocal提供了一种线程范围内的变量存储方式,每个线程都可以独立地对其进行读写而不影响其他线程。
1.创建ThreadLocal的工具类
首先,定义一个ThreadLocal变量,用于存储线程范围内的数据。例如,可以用于存储当前用户的信息。
public class RequestContext {
private static final ThreadLocal<String> userContext = new ThreadLocal<>();
/**
* 设置用户信息
* @param user
*/
public static void setUserContext(String user) {
userContext.set(user);
}
/**
* 得到用户信息
* @return
*/
public static String getUserContext() {
return userContext.get();
}
/**
* 清理用户数据
*/
public static void clear() {
userContext.remove();
}
}
2.创建拦截器
接下来,创建一个拦截器,在请求开始时将用户信息存入 ThreadLocal
,在请求结束后清除信息。
@Slf4j
@Configuration
public class MyInterceptor implements HandlerInterceptor {
@Resource
private SysUserMapper userMapper;
/**
* 添加用户信息缓存和设置ThreadLocal
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(StpUtil.isLogin()){
// 获取当前会话的 token 值
String tokenValue = StpUtil.getTokenValue();
log.info("当前会话的token值"+tokenValue);
// 获取指定 token 对应的账号id,如果未登录,则返回 null
String id = (String) StpUtil.getLoginIdByToken(tokenValue);
log.info(id);
RequestContext.setUserContext(id);
SysUser user = (SysUser) RedisUtils.get(id);
System.out.println(RequestContext.getUserContext());
if(user==null){
SysUser sysUser = userMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserId, id));
System.out.println(sysUser);
RedisUtils.set(id,sysUser,3000);
log.info(sysUser.toString());
log.info(id);
}
}
return true;
}
/**
* 清理清理ThreadLocal变量
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 清理ThreadLocal变量
RequestContext.clear();
}
}
这里我在处理Token时直接使用了第三方工具satoken,jwt携带的信息只有id信息,这个id我使用了用户id
3.总结
通过这种方式,ThreadLocal 允许你在整个请求处理期间共享数据,而不必显式地将数据传递到每一个方法中。拦截器确保了 ThreadLocal 数据的初始化和清理,避免了内存泄漏的风险。这在处理用户会话、事务管理或审计日志等需要线程隔离的场景中非常有用。