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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM