zoukankan      html  css  js  c++  java
  • SpringMVC:学习笔记(12)——ThreadLocal实现会话共享

    SpringMVC:学习笔记(12)——ThreadLocal实现会话共享

    ThreadLocal

      ThreadLocal,被称为线程局部变量。在并发编程的情况下,使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。每个Thread对象内部都维护了一个ThreadLocalMap它可以存放若干个ThreadLocal。如下为Thread源码部分:

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
    

      当我们对ThreadLocal执行set方法时,他首先做的是取当前线程的ThreadLocalMap,所以可以保证每个线程可以独享自己的ThreadLocal对象。如下为ThreadLocal源码部分:

        /**
         * Sets the current thread's copy of this thread-local variable
         * to the specified value.  Most subclasses will have no need to
         * override this method, relying solely on the {@link #initialValue}
         * method to set the values of thread-locals.
         *
         * @param value the value to be stored in the current thread's copy of
         *        this thread-local.
         */
        public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    

      那这样一来ThreadLocal就具有了一些高级特性:

    • 全局性,在当前线程中,任何一个点都可以访问到ThreadLocal的值。
    • 独立性,该线程的ThreadLocal只能被该线程访问,一般情况下其他线程访问不到。

     

    实现会话共享

    通用的思路

      在SpringMVC中,@Action方法接受了Request对象,我们可以从中取出HttpSession会话数据

    public ModelAndView getTest(HttpServletRequest request, HttpServletResponse response){
         String userId = request.getSession().getAttribute("user").toString();
    }
    

      但要是我们在一个普通的方法中想访问到HttpSession对象就会很难了,如果我们在请求到来时用Filter把HttpSession保存到ThreadLocal中,利用ThreadLocal的全局性,不是就可以在普通方法中使用了吗?当然我们最好将其封装一个类,来方便以后随时调用和迭代更新。

    HttpContext 

      我们创建一个HttpContext类,来将Request、Response、Session、Cookies等对象进行封装,方便以后直接使用。

    public class HttpContext {
        private HttpServletRequest request;
        private HttpServletResponse response;
        private final static ThreadLocal<HttpContext> contextContainer = new ThreadLocal<HttpContext>();
        /**
         * 初始化
         */
        public static HttpContext begin(HttpServletRequest req, HttpServletResponse res) {
            HttpContext context = new HttpContext();
            context.request = req;
            context.response = res;
            contextContainer.set(context);
            return context;
        }
        public static HttpContext get(){
            return contextContainer.get();
        }
        /**
         * 销毁
         */
        public void end() {
            this.request = null;
            this.response = null;
            contextContainer.remove();
        }
        public ServletContext getContext() {
            return this.request.getServletContext();
        }
        public HttpSession getSession() {
            return this.request.getSession(false);
        }
        public HttpServletRequest getRequest() {
            return this.request;
        }
        public HttpServletResponse getResponse() {
            return this.response;
        }
        public Map<String, Cookie> getCookies() {
            Map<String, Cookie> map = new HashMap<String, Cookie>();
            Cookie[] cookies = this.request.getCookies();
            if(cookies != null)
                for(Cookie ck : cookies) {
                    map.put(ck.getName(), ck);
                }
            return map;
        }
    }

    WebFilter

      过滤器是实现会话共享的前提,我们在里面只是绑定一下请求对象。

    /**
     * HttpContext全局过滤器
     */
    public class ContextFilter implements Filter{
        public void init(FilterConfig filterConfig) throws ServletException {
        }
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest)servletRequest;
            HttpServletResponse res = (HttpServletResponse)servletResponse;
            HttpContext.begin(req, res);
            filterChain.doFilter(servletRequest, servletResponse);
        }
        public void destroy() {
            HttpContext.get().end();
        }
    }

    使用

      现在,我们可以在一个普通的Java方法中,使用会话对象,如果我们做一个简单的Dispatcher,然后使用Response对象,那么一个后端框架便横空出世了!

    /**
    * 获得当前登录人员的凭证信息
    */
    public static String getId(){
        HttpSession session = HttpContext.get().getSession();
        Object obj = null;
        if (null != session){
            obj = session.getAttribute("USERID");
        }
        if (null == obj) {
            return null;
       }
       return obj.toString();
    }
    

     

    参考链接

    http://www.blackzs.com/archives/740

  • 相关阅读:
    UITableView的简单使用
    Oracle相关博客转移
    使用Outlook 2010,拖拽大于20M附件发生“附件大小超过了允许的范围”提示的解决方法
    Use OpenLDAP as security provider in Oracle UCM 11g
    PostBuild event不能注册到全局缓存解决办法
    WIN7下丢失的光驱解决办法:由于其配置信息不完整或已损坏,Windows 无法启动这个硬件设备
    我与计算机的故事
    nova http 409 虚拟机状态重置
    百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换(JS版代码)
    未能从程序集加载类型
  • 原文地址:https://www.cnblogs.com/MrSaver/p/11191028.html
Copyright © 2011-2022 走看看