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

SpringMVC:学习笔记(12)——ThreadLocal实现会话共享的更多相关文章

  1. springmvc学习笔记(12)-springmvc注解开发之包装类型參数绑定

    springmvc学习笔记(12)-springmvc注解开发之包装类型參数绑定 标签: springmvc springmvc学习笔记12-springmvc注解开发之包装类型參数绑定 需求 实现方 ...

  2. Qt学习笔记12:基本会话框4——总结

    文件对话框静态函数 QString QFileDialog::getOpenFileName{ QWidget *parent = 0; //标准文件对话框的父窗口 const QString &am ...

  3. Spring MVC 学习笔记12 —— SpringMVC+Hibernate开发(1)依赖包搭建

    Spring MVC 学习笔记12 -- SpringMVC+Hibernate开发(1)依赖包搭建 用Hibernate帮助建立SpringMVC与数据库之间的联系,通过配置DAO层,Service ...

  4. SpringMVC学习笔记之二(SpringMVC高级参数绑定)

    一.高级参数绑定 1.1 绑定数组 需求:在商品列表页面选中多个商品,然后删除. 需求分析:功能要求商品列表页面中的每个商品前有一个checkbok,选中多个商品后点击删除按钮把商品id传递给Cont ...

  5. 并发编程学习笔记(8)----ThreadLocal的使用及源码分析

    1. ThreadLocal的理解 ThreadLocal,顾名思义,就是线程的本地变量,ThreadLocal会为每个线程创建一个本地变量副本,使得使用ThreadLocal管理的变量在多线程的环境 ...

  6. springmvc学习笔记(10)-springmvc注解开发之商品改动功能

    springmvc学习笔记(10)-springmvc注解开发之商品改动功能 标签: springmvc springmvc学习笔记10-springmvc注解开发之商品改动功能 需求 开发mappe ...

  7. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  8. 史上最全的SpringMVC学习笔记

    SpringMVC学习笔记---- 一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar包. 2.添加Web.xml配置文件中关于Spring ...

  9. springmvc学习笔记--REST API的异常处理

    前言: 最近使用springmvc写了不少rest api, 觉得真是一个好框架. 之前描述的几篇关于rest api的文章, 其实还是不够完善. 比如当遇到参数缺失, 类型不匹配的情况时, 直接抛出 ...

随机推荐

  1. Hive 数据类型与文件格式

    一.基本数据类型 1.基本数据类型 Tinyint  1byte有符号整数  比如20 Smalint 2byte有符号整数 比如20 Int          4byte有符号整数 比如20 Big ...

  2. PostgreSQL物理坏块和文件损坏案例分享

    作者简介 王睿操,平安好医数据库架构岗,多年postgresql数据库运维开发工作.曾就职于中国民航信息,迪卡侬.对其他数据库产品也有一定的涉猎. 背景 笔者最近发现很多朋友经常遇到PostgreSQ ...

  3. codevs:2849 素数判定 3:输入一个正整数x(3<=x<=100000),判断x是否是质数,如果是质数则输出信息“prime”,否则输出“composite”。

    #include<iostream>#include<cstdio>#include<cmath>using namespace std;int a[2];int ...

  4. 洛谷 P1230 智力大冲浪 题解

    P1230 智力大冲浪 题目描述 小伟报名参加中央电视台的智力大冲浪节目.本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者 \(m\)元.先不要太高兴!因为这些钱还不一定都是你的 ...

  5. AtCoder Grand Contest 009 题解

    传送门 为啥这场题目少一点啊-- \(A\) 易知增加的数前面肯定比后面大,那么我们倒着做,然后维护一下最小要加多少就可以了 typedef long long ll; const int N=1e5 ...

  6. 洛谷P1714切蛋糕

    题目 该题目就是求这n个数的前缀和所组成的数组的所有子区间的左端点和右端点相差不超过m,且他们的前缀和差最大,求出这个最大值即可. 而朴素算法肯定会T,而我们发现如果前缀和最大的话,则前缀和的值一定是 ...

  7. (19)打鸡儿教你Vue.js

    了解vue2.x的核心技术 建立前端组件化的思想 常用的vue语法 vue-router,vuex,vue-cli 使用vue-cli工具 Vue框架常用知识点 vue核心技术 集成Vue 重点看,重 ...

  8. UOJ226. 【UR #15】奥林匹克环城马拉松 [组合数学,图论]

    UOJ 思路 我们知道关于有向图欧拉回路计数有一个结论:在每个点入度等于出度的时候,答案就是 \[ t_w(G)\prod (deg_i-1)! \] 其中\(t_w(G)\)是以某个点为根的树形图个 ...

  9. nginx 配置的server_name参数

    nginx中的server_name指令主要用于配置基于名称虚拟主机. 一 匹配顺序,server_name指令在接到请求后的匹配顺序如下: 1.确切的server_name匹配,例如: server ...

  10. Ubuntu16.04忘记MySQL5.7的root用户密码之解决方案

    其实也就四步,如下: 修改配置文件 sudo vimi /etc/mysql/mysql.conf.d/mysqld.cnf 并在 在[mysqld]下方的skip-external-locking下 ...