首页 > 学院 > 开发设计 > 正文

ThreadLocal应用之一-----利用拦截器或过滤器设置请求上下文

2019-11-08 20:20:53
字体:
来源:转载
供稿:网友

之前一直使用ThreadLocal进行请求上下文的设置,只知道ThreadLocal是线程安全的每个线程获取的是本线程所对应的值,没有去深入了解ThreadLocal的具体实现,现在翻看转载的博客并参照源码,彻底明白了其原理,记录如下。

ThreadLocal存取原理分析

先看如下业务代码:

/** * 应用基本上下文 * @author rambo.pan */public class HttpContext { /** * 静态变量,作为各个线程中的Map的key,每个HttpContext实例为相应的value */ PRivate static final ThreadLocal<HttpContext> currentContext = new ThreadLocal<HttpContext>(); private boolean isLogin; private String userId; private UserInfo userInfo; private VpalRequestHeader header; private String client; /** * 获取ThreadLocal中当前线程对应的HttpContext实例 * @param throwFlag set方法传入false,当context为空时new一个新实例;get方法传入true,当context为空时throw异常 * @return */ private static HttpContext getContext(boolean throwFlag){ HttpContext context = currentContext.get(); if (context == null) { if (throwFlag) { throw new RuntimeException("context can not be access now"); }else { context = new HttpContext(); } } return context; } /** * 获取ThreadLocal中当前线程对应的HttpContext实例:用户登录标识 * @return */ public static boolean isLogin() { HttpContext context = getContext(true); return context.isLogin; }}

我以前的理解是:ThreadLocal实例是和线程关联的,每个线程有单独的ThreadLocal实例,所以对ThreadLocal定义成static final 感到很不理解,因为这样定义就表明:当HttpContext的字节码被装载入虚拟机的时候,其类变量currentContext就会被初始化且仅初始化一次,那么每个线程用key都是一样的了啊,如此推断每个线程拿到的value也都是一样的了。 实际上,这个理解的前半段是没问题的,偏差出现在后面,key虽然是一样的,但是Map却是每个线程都不一样的。看如下分析:

ThreadLocal的get方法实现:
/***首先获取当前线程*然后获取当前线程对象的属性:ThreadLocalMap*再从该Map中取得value,而key正是ThreadLocal的引用*由此可以很清楚明白,每个线程在ThreadLocal.get()时,所用的Map对象都是不同的,所以尽管key相同,得到的value也是不同的。*/public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue();}

拦截器设置

public class UserContextInterceptor implements HandlerInterceptor{ private Logger logger = LoggerFactory.getLogger(getClass()); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //1.获取header里的参数并设置到ThreadLocal中 VpalRequestHeader header = mapHeader(request); HttpContext.setHeader(header); //2.校验sessionId 合法性 //3.获取并设置用户信息 UserInfo userInfo = getLoginUserInfo(request,response); HttpContext.setUserInfo(userInfo); logger.debug(String.format("请求%s进入",request.getRequestURI())); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { //设置response的Header信息 response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); logger.info("请求%s返回值:%s",request.getRequestURI(),request.getAttribute("result")); }}
上一篇:每日一题(6):

下一篇:01ZigBee简介

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表