个人博客开发问题记录:ThreadLocal获取用户数据失败
项目场景:
在用户登录成功后将用户ID存入了ThreadLocal之中便于后续程序直接获取用户数据
问题描述
在用户登录成功后将用户ID存入了ThreadLocal之中,但是后续在其它请求获取ThreadLocal中的值的时候发现都是null
原因分析:
由于Tomcat是多线程处理请求,所以前端的异步请求导致,登录的请求和其它请求不是同一个线程处理,导致获取不到ThreadLocal中的值
解决方案:
由于是第一次自己使用ThreadLocal所以搞错了ThreadLocal存储用户数据的位置。
直接在LoginController中设置ThreadLocal中的用户数据会导致其它请求获取不到。应该将设置ThreadLocal存储数据的位置调整到拦截器中,这样一个就可以获取到用户数据了。
总结一句话:需要使用ThreadLocal数据的请求不能直接放行,需要在拦截器内设置ThreadLocal中的数据,并且在使用结束后释放资源。
参考代码:
ThreadLocalUtils
public class ThreadLocalUtils {private static final ThreadLocal<String> CURRENT = new InheritableThreadLocal<>();public static void setUserInfo(String userRuntime) {CURRENT.set(userRuntime);}public static String getUserInfo() {return CURRENT.get();}public static void clearUserInfo() {CURRENT.remove();}}
LoginInterceptor
public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 放行OPTIONS请求if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {return true;}// 其他拦截逻辑(如登录校验)String token = request.getHeader("Authorization");log.info("拦截器获取到的token:{}", token);if (token == null || token.isEmpty()) {throw new AuthenticationExceptions(HTTPStateCodeEnum.AUTHENTICATION_FAIL.getMessage());}// 校验token合法性if (!JWTUtils.verify(token)) {throw new AuthenticationExceptions(HTTPStateCodeEnum.AUTHENTICATION_FAIL.getMessage());}// 将用户信息存入ThreadLocalThreadLocalUtils.setUserInfo(String.valueOf(JWTUtils.decodeToken(token)));return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception {if (ThreadLocalUtils.getUserInfo() != null) {ThreadLocalUtils.clearUserInfo();}}
}