最近项目设计集群,实现了一下session的共享功能,其原理是将session保存到分布式缓存数据库中如:redis, memcache等,然后多个服务器tomcat
每次请求都通过NoSql数据库查询,如果存在,则获取值;反之存放值。
我是通过redis来实现session的共享,其主要有一下两种方法:
1、通过tomcat服务器的拓展功能实现这种方式比较简单,主要是通过继承session的ManagerBase类,实现重写session相关的方法,这种比较简单,参考源码链接(http://download.csdn.net/detail/fengshizty/9417242)。
2、通过filter拦截request请求实现下面主要介绍这样实现方式:(1)写HttpSessionWrapper实现HttpSession接口,实现里面session相关的方法。(2)写HttpServletRequestWrapper继承javax.servlet.http.HttpServletRequestWrapper类,重写对于session  相关的方法。(3)写SessionFilter拦截配置的请求url,过去cookie中的sessionId,如果为空,对此次请求重写生成一个新的sessionId,在sessionId构造新的HttpServletRequestWrapper对象。(4)写SessionService实现session到redis的保存和过去,其key为sessionId,value为session对于的Map。
3、代码实现(1)HttpSessionWrapper
/*** 创建时间:2016年1月21日 下午7:55:41* * @author andy* @version 2.2*/public class HttpSessionWrapper implements HttpSession {private String sid = "";private HttpSession session;private HttpServletRequest request;private HttpServletResponse response;private Map<String, Object> map = null;private SessionService sessionService = (SessionService) SpringContextHolder.getBean("sessionService");public HttpSessionWrapper() {}public HttpSessionWrapper(HttpSession session) {this.session = session;}public HttpSessionWrapper(String sid, HttpSession session) {this(session);this.sid = sid;}public HttpSessionWrapper(String sid, HttpSession session,HttpServletRequest request, HttpServletResponse response) {this(sid, session);this.request = request;this.response = response;}private Map<String, Object> getSessionMap() {if (this.map == null) {this.map = sessionService.getSession(this.sid);}return this.map;}@Overridepublic Object getAttribute(String name) {if (this.getSessionMap() != null) {Object value = this.getSessionMap().get(name);return value;}return null;}@Overridepublic void setAttribute(String name, Object value) {this.getSessionMap().put(name, value);sessionService.saveSession(this.sid, this.getSessionMap());}@Overridepublic void invalidate() {this.getSessionMap().clear();sessionService.removeSession(this.sid);CookieUtil.removeCookieValue(this.request,this.response, GlobalConstant.JSESSIONID);}@Overridepublic void removeAttribute(String name) {this.getSessionMap().remove(name);sessionService.saveSession(this.sid, this.getSessionMap()); }@Overridepublic Object getValue(String name) {return this.session.getValue(name);}@SuppressWarnings("unchecked")@Overridepublic Enumeration getAttributeNames() {return (new Enumerator(this.getSessionMap().keySet(), true));}@Overridepublic String[] getValueNames() {return this.session.getValueNames();}@Overridepublic void putValue(String name, Object value) {this.session.putValue(name, value);}@Overridepublic void removeValue(String name) {this.session.removeValue(name);}@Overridepublic long getCreationTime() {return this.session.getCreationTime();}@Overridepublic String getId() {return this.sid;}@Overridepublic long getLastAccessedTime() {return this.session.getLastAccessedTime();}@Overridepublic ServletContext getServletContext() {return this.session.getServletContext();}@Overridepublic void setMaxInactiveInterval(int interval) {this.session.setMaxInactiveInterval(interval);}@Overridepublic int getMaxInactiveInterval() {return this.session.getMaxInactiveInterval();}@Overridepublic HttpSessionContext getSessionContext() {return this.session.getSessionContext();}@Overridepublic boolean isNew() {return this.session.isNew();}}
(2)HttpServletRequestWrapper实现
/*** 创建时间:2016年1月22日 下午7:52:29* * @author andy* @version 2.2*/public class HttpServletRequestWrapper extendsjavax.servlet.http.HttpServletRequestWrapper {private HttpSession session;private HttpServletRequest request;private HttpServletResponse response;private String sid = "";public HttpServletRequestWrapper(HttpServletRequest request) {super(request);}public HttpServletRequestWrapper(String sid, HttpServletRequest request) {super(request);this.sid = sid;}public HttpServletRequestWrapper(String sid, HttpServletRequest request,HttpServletResponse response) {super(request);this.request = request;this.response = response;this.sid = sid;if (this.session == null) {this.session = new HttpSessionWrapper(sid, super.getSession(false),request, response);}}@Overridepublic HttpSession getSession(boolean create) {if (this.session == null) {if (create) {this.session = new HttpSessionWrapper(this.sid,super.getSession(create), this.request, this.response);return this.session;} else {return null;}}return this.session;}@Overridepublic HttpSession getSession() {if (this.session == null) {this.session = new HttpSessionWrapper(this.sid, super.getSession(),this.request, this.response);}return this.session;}}
(3)SessionFilter拦截器的实现
public class SessionFilter extends OncePerRequestFilter implements Filter {private static final Logger LOG = Logger.getLogger(SessionFilter.class);@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {//从cookie中获取sessionId,如果此次请求没有sessionId,重写为这次请求设置一个sessionIdString sid = CookieUtil.getCookieValue(request, GlobalConstant.JSESSIONID);if(StringUtils.isEmpty(sid) || sid.length() != 36){sid = StringUtil.getUuid();CookieUtil.setCookie(request, response, GlobalConstant.JSESSIONID, sid, 60 * 60); }//交给自定义的HttpServletRequestWrapper处理filterChain.doFilter(new HttpServletRequestWrapper(sid, request, response), response);}}
(4)SessionService实现session从redis的读写存储
public class SessionService {private final static Logger LOG = Logger.getLogger(SessionService.class);private JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();@Autowiredprivate RedisTemplate<Serializable, Serializable> redisTemplate;@SuppressWarnings("unchecked")public Map<String, Object> getSession(String sid) {Map<String, Object> session = new HashMap<String, Object>();try {Object obj = redisTemplate.opsForValue().get(RedisKeyUtil.SESSION_DISTRIBUTED_SESSIONID + sid);if(obj != null){obj = jdkSerializer.deserialize((byte[])obj);session = (Map<String, Object>) obj;}} catch (Exception e) {LOG.error("Redis获取session异常" + e.getMessage(), e.getCause());}return session;}public void saveSession(String sid, Map<String, Object> session) {try {redisTemplates.opsForValue().set(RedisKeyUtil.SESSION_DISTRIBUTED_SESSIONID + sid,jdkSerializer.serialize(session), RedisKeyUtil.SESSION_TIMEOUT,TimeUnit.MINUTES);} catch (Exception e) {LOG.error("Redis保存session异常" + e.getMessage(), e.getCause());}}public void removeSession(String sid) {try {redisTemplates.delete(RedisKeyUtil.SESSION_DISTRIBUTED_SESSIONID + sid);} catch (Exception e) {LOG.error("Redis删除session异常" + e.getMessage(), e.getCause());}}
}
(5)Session的拦截配置,一般的我们只需要拦截我们定义的拦截请求拦截,而不需要所有的都需要拦截。在web.xml中配置SessionFilter。
<filter><filter-name>sessionFilter</filter-name><filter-class>org.andy.shop.session.SessionFilter</filter-class></filter><filter-mapping><filter-name>sessionFilter</filter-name><url-pattern>*.do</url-pattern></filter-mapping>

附:设计到的工具类

1、StringUtil工具类

/*** String工具类* * @author andy* @date 2015-5-16 下午4:04:22* */
public class StringUtil {private StringUtil() {super();}/*** 出去null和""* @param src* @return*/public static String formatNull(String src) {return (src == null || "null".equals(src)) ? "" : src;}/*** 判断字符串是否为空的正则表达式,空白字符对应的unicode编码*/private static final String EMPTY_REGEX = "[\\s\\u00a0\\u2007\\u202f\\u0009-\\u000d\\u001c-\\u001f]+";/*** 验证字符串是否为空* * @param input* @return*/public static boolean isEmpty(String input) {return input == null || input.equals("") || input.matches(EMPTY_REGEX);}public static boolean isNotEmpty(String input){return !isEmpty(input);}public static String getUuid() {return UUID.randomUUID().toString();}
}

2、Cookie管理CookieUtil工具类

/*** 创建时间:2016年1月22日 下午8:33:56* * @author andy* @version 2.2*/public class CookieUtil {private static final String KEY = "jkdflsffff()kldkjapfdY=::$B+DUOWAN";private HttpServletRequest request;private HttpServletResponse response;private static String domain = "andy.com";public CookieUtil(HttpServletRequest request, HttpServletResponse response) {this.request = request;this.response = response;}/*** 保存cookie* @param request* @param response* @param name cookie名称* @param value cookie值* @param seconds 过期时间(单位秒) -1代表关闭浏览器时cookie即过期*/public static void setCookie(HttpServletRequest request,HttpServletResponse response, String name, String value, int seconds) {if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value))return;Cookie cookie = new Cookie(name, value);//cookie.setDomain(domain);cookie.setMaxAge(seconds); cookie.setPath("/");response.setHeader("P3P","CP='IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT'");response.addCookie(cookie);}/*** 过去cookie中保存的值* @param name* @return* @throws UnsupportedEncodingException*/public String getCookieValue(String name)throws UnsupportedEncodingException {Cookie cookies[] = request.getCookies();if (cookies != null) {for (int i = 0; i < cookies.length; i++) {if (name.equalsIgnoreCase(cookies[i].getName())) {return cookies[i].getValue();}}}return "";}/*** 设置加密的cookie* @param name cookie名称* @param value cookie值* @param seconds 过期时间 -1代表关闭浏览器时cookie即过期*/public void setCheckCodeCookie(String name, String value, int seconds) {if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value)) {return;}String md5Value = MD5Utils.getMD5(KEY + value);Cookie cookie = new Cookie(name, md5Value);//cookie.setDomain(domain);cookie.setMaxAge(seconds);cookie.setPath("/");response.addCookie(cookie);}/*** 校验加密的cookie* @param name* @param value* @return*/public boolean checkCodeCookie(String name, String value) {if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value)) {return false;}boolean result = false;String cookieValue = getCookieValue(request, name);if (MD5Utils.getMD5(KEY + value).equalsIgnoreCase(cookieValue)) {result = true;}return result;}/*** 获取cookie值* @param request* @param name* @return*/public static String getCookieValue(HttpServletRequest request, String name) {try {Cookie cookies[] = request.getCookies();if (cookies != null) {for (int i = 0; i < cookies.length; i++) {if (name.equalsIgnoreCase(cookies[i].getName())) {return cookies[i].getValue();}}}} catch (Exception e) {}return "";}/*** 移除客户端的cookie* @param request* @param response* @param name*/public static void removeCookieValue(HttpServletRequest request,HttpServletResponse response, String name) {try {Cookie cookies[] = request.getCookies();if (cookies != null && cookies.length > 0) {for (Cookie cookie : cookies) {if (name.equalsIgnoreCase(cookie.getName())) {cookie = new Cookie(name, null);cookie.setMaxAge(0);cookie.setPath("/");//cookie.setDomain(domain);response.addCookie(cookie);break;}}}} catch (Exception e) {e.printStackTrace();}}
}

3、redis键key设置类RedisKeyUtil

/*** 创建时间:2015年9月22日 下午4:51:11* * @author andy* @version 2.2*/public class RedisKeyUtil {public static final String SESSION_DISTRIBUTED_SESSIONID = "session:distributed:"; //分布式session sessionid -- sessionvaluepublic static final Integer SESSION_TIMEOUT = 2; //session 失效时间2小时}

4、分布式session常量设置类GlobalConstant

/*** 创建时间:2016年1月23日 上午11:16:56* * 分布式session常量* * @author andy* @version 2.2*/public class GlobalConstant {public static final String USER_SESSION_KEY = "user_session_key";//用户session信息public static final String JSESSIONID = "YHMJSESSIONID"; //jsessionid
}

分布式session在redis执行结果:

Redis实现分布式session功能的共享相关推荐

  1. 170222、使用Spring Session和Redis解决分布式Session跨域共享问题

    使用Spring Session和Redis解决分布式Session跨域共享问题 原创 2017-02-27 徐刘根 Java后端技术 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用 ...

  2. 使用Spring Session和Redis解决分布式Session跨域共享问题

    大家可以关注一下公众号"Java架构师秘籍" 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用的均衡算法有IP_Hash.轮训.根据权重.随机等.不管对于哪一种负载 ...

  3. 场景应用:利用Redis实现分布式Session

    文章目录 原理:Redis实现分布式Session web开发session 分布式session同步问题 分布式session解决方案 实战:Redis实现分布式Session 技术栈:Spring ...

  4. Tornado 自定义session,与一致性哈希 ,基于redis 构建分布式 session框架

    Tornado 自定义session,与一致性哈希 ,基于redis 构建分布式 session import tornado.ioloopimport tornado.webfrom myhash ...

  5. SpringSession+redis解决分布式session不一致性问题

    七.案例实战:SpringSession+redis解决分布式session不一致性问题 步骤1:加入SpringSession.redis的依赖包 <dependency><gro ...

  6. springboot+redis实现分布式session共享

    官方文档,它是spring session项目的redis相关的一个子文档:https://docs.spring.io/spring-session/docs/2.0.0.BUILD-SNAPSHO ...

  7. 8.redis解决分布式session问题 、redis在项目中难点

    a.什么是session session是一种会话技术,我们知道http是无状态协议的,就是这次连接传输数据后,下次连接服务器是不知道这次的请求是谁的,因此我们要做一个标记,让服务器知道每次请求是哪个 ...

  8. 如何利用Redis实现分布式Session?

    在web开发中,我们会把用户的登录信息存储在「session」里.而session是依赖于「cookie」的,即服务器创建session时会给它分配一个唯一的ID,并且在响应时创建一个cookie用于 ...

  9. Spring Session + Redis实现分布式Session共享

    2019独角兽企业重金招聘Python工程师标准>>> 通常情况下,Tomcat.Jetty等Servlet容器,会默认将Session保存在内存中.如果是单个服务器实例的应用,将S ...

  10. Redis实现分布式Session管理

    管理机制 redis的session管理是利用spring提供的session管理解决方案,将一个应用session交给Redis存储,整个应用中所有session的请求都会去redis中获取对应的s ...

最新文章

  1. 学霸学长如何第一时间收到接口报错?不用测试妹子再质疑你是不是接口挂了
  2. java分页查询oracle_Java中实现Oracle分页查询
  3. 使用 CXF 做 webservice 简单例子
  4. 我喜欢阅读和计算机英语,关于自考中的计算机专业
  5. nodepad 关闭语法检查
  6. 深入理解Java类加载器(2)
  7. Documentation/x86/kernel-stacks
  8. bag文件加载及可视化显示
  9. [大牛翻译系列]Hadoop(7)MapReduce:抽样(Sampling)
  10. qt for python对比pyqt_PyQt4和electron的第二轮对比
  11. SpringBoot整合JWT实现前后端Token验证
  12. 第三方支付清算的信息流与资金流
  13. 一文打尽PHP代码加密方式
  14. Wibbitz:根据网页文字生成在线视频(转)
  15. php imap函数,Imap是什么意思,php imap 函数详解(2)
  16. 江苏农村商业银行计算机类笔试考什么时候,2020江苏农商行春季校园招聘笔试考什么?...
  17. vue3 项目中如何输出webpack的config.js
  18. windows nao naoqi SDK 配置
  19. 广汽本田定价混乱,让消费者对于凌派和飞度无所适从
  20. linux unrar 密码,linux下使用unrar命令解压*.rar格式文件(示例代码)

热门文章

  1. 【易实战】Spring Cloud微服务架构12要素应用 Twelve‑Factor App
  2. mysql db for python_Python使用MySQLdb for Python操作数据库教程
  3. js导出的xlsx无法打开_遇到U盘无法打开,属性显示0字节这样的问题?数据该如何导出?...
  4. Towards Fully 8-bit Integer Inference for the Transformer Model
  5. 编写程序销毁一个单链表
  6. 前缀无歧义编码(PFC)
  7. How to Become a Better Learner
  8. 32 开漏输出 高电平_MCU输入输出端口设置
  9. Spring Cloud随记---分布式配置中心初探--一个单节点的配置中心
  10. 结构风险最小和VC维理论的解释