最近在开发项目时需要在拦截器中请求认证服务判断token的有效性并获取用户信息,但是拿到用户信息后需要传递给Controller层或者Service层去使用。一开始想到了使用header和session传递用户信息,但是感觉不是很优雅,有点low,最后想到了使用ThreadLocal多线程上下文传递参数。
ThreadLocal是什么?
ThreadLocal是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不同的变量值完成操作的场景。
ThreadLocal类提供如下几个核心方法:
public T get()
public void set(T value)
public void remove()
get()方法用于获取当前线程的副本变量值。
set()方法用于保存当前线程的副本变量值。
remove()方法移除当前线程的副本变量值。
在SpringBoot项目中使用ThreadLocla拦截器传递数据
创建用户向下文实体类
package cn.ilren.resource.common;
import cn.ilren.resource.pojo.LoginUser;
/**
* 使用线程上下文在线程内共享用户信息
*/
public class UserContext {
//把构造函数私有化,外部不能new
private UserContext() {
}
private static final ThreadLocal<LoginUser> context = new ThreadLocal<LoginUser>();
/**
* 存放用户信息
*
* @param user
*/
public static void set(LoginUser user) {
context.set(user);
}
/**
* 获取用户信息
*
* @return
*/
public static LoginUser get() {
return context.get();
}
/**
* 清除当前线程内引用,防止内存泄漏
*/
public static void remove() {
context.remove();
}
}
2.在拦截器中获取用户信息并将用户信息放置在UserContext线程上下文中
package cn.ilren.resource.interceptor;
import cn.ilren.resource.common.UserContext;
import cn.ilren.resource.pojo.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 拦截器
*/
@Slf4j
public class ResourceInterceptor implements HandlerInterceptor {
/**
* 在请求处理之前进行调用(Controller方法调用之前)
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
try {
······
LoginUser user = ······ ;//从请求认证服务获取用户信息
UserContext.set(user);
return Boolean.TRUE;
} catch (Exception e) {
log.error("拦截器出错", e);
return Boolean.FALSE;
}
}
/**
* 请求处理之后进行调用(Controller方法调用之后)
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView mv)
throws Exception {
}
/**
* 在整个请求结束之后被调用(主要是用于进行资源清理工作)
* 一定要在请求结束后调用remove清除当前线程的副本变量值,否则会造成内存泄漏
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception ex)
throws Exception {
UserContext.remove();
}
}
3.在Controller或Service层使用当前线程上下文获取用户信息
LoginUser user = UserContext.get();