热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Redis实现分布式session功能的共享

最近项目设计集群,实现了一下session的共享功能,其原理是将session保存到分布式缓存数据库中如:redis,mem

最近项目设计集群,实现了一下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 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 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 redisTemplate;@SuppressWarnings("unchecked")public Map getSession(String sid) {Map session = new HashMap();try {Object obj = redisTemplate.opsForValue().get(RedisKeyUtil.SESSION_DISTRIBUTED_SESSIONID + sid);if(obj != null){obj = jdkSerializer.deserialize((byte[])obj);session = (Map) obj;}} catch (Exception e) {LOG.error("Redis获取session异常" + e.getMessage(), e.getCause());}return session;}public void saveSession(String sid, Map 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>sessionFilterfilter-name><filter-class>org.andy.shop.session.SessionFilterfilter-class>filter><filter-mapping><filter-name>sessionFilterfilter-name>*.dofilter-mapping>


附&#xff1a;设计到的工具类

1、StringUtil工具类

/*** String工具类* * &#64;author andy* &#64;date 2015-5-16 下午4:04:22* */
public class StringUtil {private StringUtil() {super();}/*** 出去null和""* &#64;param src* &#64;return*/public static String formatNull(String src) {return (src &#61;&#61; null || "null".equals(src)) ? "" : src;}/*** 判断字符串是否为空的正则表达式&#xff0c;空白字符对应的unicode编码*/private static final String EMPTY_REGEX &#61; "[\\s\\u00a0\\u2007\\u202f\\u0009-\\u000d\\u001c-\\u001f]&#43;";/*** 验证字符串是否为空* * &#64;param input* &#64;return*/public static boolean isEmpty(String input) {return input &#61;&#61; 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工具类

/*** 创建时间&#xff1a;2016年1月22日 下午8:33:56* * &#64;author andy* &#64;version 2.2*/public class COOKIEUtil {private static final String KEY &#61; "jkdflsffff()kldkjapfdY&#61;::$B&#43;DUOWAN";private HttpServletRequest request;private HttpServletResponse response;private static String domain &#61; "andy.com";public COOKIEUtil(HttpServletRequest request, HttpServletResponse response) {this.request &#61; request;this.response &#61; response;}/*** 保存COOKIE* &#64;param request* &#64;param response* &#64;param name COOKIE名称* &#64;param value COOKIE值* &#64;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 &#61; new COOKIE(name, value);//COOKIE.setDomain(domain);COOKIE.setMaxAge(seconds); COOKIE.setPath("/");response.setHeader("P3P","CP&#61;&#39;IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT&#39;");response.addCOOKIE(COOKIE);}/*** 过去COOKIE中保存的值* &#64;param name* &#64;return* &#64;throws UnsupportedEncodingException*/public String getCOOKIEValue(String name)throws UnsupportedEncodingException {COOKIE COOKIEs[] &#61; request.getCOOKIEs();if (COOKIEs !&#61; null) {for (int i &#61; 0; i if (name.equalsIgnoreCase(COOKIEs[i].getName())) {return COOKIEs[i].getValue();}}}return "";}/*** 设置加密的COOKIE* &#64;param name COOKIE名称* &#64;param value COOKIE值* &#64;param seconds 过期时间 -1代表关闭浏览器时COOKIE即过期*/public void setCheckCodeCOOKIE(String name, String value, int seconds) {if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value)) {return;}String md5Value &#61; MD5Utils.getMD5(KEY &#43; value);COOKIE COOKIE &#61; new COOKIE(name, md5Value);//COOKIE.setDomain(domain);COOKIE.setMaxAge(seconds);COOKIE.setPath("/");response.addCOOKIE(COOKIE);}/*** 校验加密的COOKIE* &#64;param name* &#64;param value* &#64;return*/public boolean checkCodeCOOKIE(String name, String value) {if (StringUtils.isEmpty(name) || StringUtils.isEmpty(value)) {return false;}boolean result &#61; false;String COOKIEValue &#61; getCOOKIEValue(request, name);if (MD5Utils.getMD5(KEY &#43; value).equalsIgnoreCase(COOKIEValue)) {result &#61; true;}return result;}/*** 获取COOKIE值* &#64;param request* &#64;param name* &#64;return*/public static String getCOOKIEValue(HttpServletRequest request, String name) {try {COOKIE COOKIEs[] &#61; request.getCOOKIEs();if (COOKIEs !&#61; null) {for (int i &#61; 0; i if (name.equalsIgnoreCase(COOKIEs[i].getName())) {return COOKIEs[i].getValue();}}}} catch (Exception e) {}return "";}/*** 移除客户端的COOKIE* &#64;param request* &#64;param response* &#64;param name*/public static void removeCOOKIEValue(HttpServletRequest request,HttpServletResponse response, String name) {try {COOKIE COOKIEs[] &#61; request.getCOOKIEs();if (COOKIEs !&#61; null && COOKIEs.length > 0) {for (COOKIE COOKIE : COOKIEs) {if (name.equalsIgnoreCase(COOKIE.getName())) {COOKIE &#61; 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

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

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

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

分布式session在redis执行结果&#xff1a;
redis中session保存结果


推荐阅读
  • 本文详细探讨了在微服务架构中,使用Feign进行远程调用时出现的请求头丢失问题,并提供了具体的解决方案。重点讨论了单线程和异步调用两种场景下的处理方法。 ... [详细]
  • 远程过程调用(RPC)是一种允许客户端通过网络请求服务器执行特定功能的技术。它简化了分布式系统的交互,使开发者可以像调用本地函数一样调用远程服务,并获得返回结果。本文将深入探讨RPC的工作原理、发展历程及其在现代技术中的应用。 ... [详细]
  • 深入理解 .NET 中的中间件
    中间件是插入到应用程序请求处理管道中的组件,用于处理传入的HTTP请求和响应。它在ASP.NET Core中扮演着至关重要的角色,能够灵活地扩展和自定义应用程序的行为。 ... [详细]
  • Java项目分层架构设计与实践
    本文探讨了Java项目中应用分层的最佳实践,不仅介绍了常见的三层架构(Controller、Service、DAO),还深入分析了各层的职责划分及优化建议。通过合理的分层设计,可以提高代码的可维护性、扩展性和团队协作效率。 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • 并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
    Java并发编程实践目录并发编程01——ThreadLocal并发编程02——ConcurrentHashMap并发编程03——阻塞队列和生产者-消费者模式并发编程04——闭锁Co ... [详细]
  • 本文详细介绍了JSP(Java Server Pages)的九大内置对象及其功能,探讨了JSP与Servlet之间的关系及差异,并提供了实际编码示例。此外,还讨论了网页开发中常见的编码转换问题以及JSP的两种页面跳转方式。 ... [详细]
  • 本文详细探讨了 org.apache.hadoop.ha.HAServiceTarget 类中的 checkFencingConfigured 方法,包括其功能、应用场景及代码示例。通过实际代码片段,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 我有一个SpringRestController,它处理API调用的版本1。继承在SpringRestControllerpackagerest.v1;RestCon ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 深入解析ESFramework中的AgileTcp组件
    本文详细介绍了ESFramework框架中AgileTcp组件的设计与实现。AgileTcp是ESFramework提供的ITcp接口的高效实现,旨在优化TCP通信的性能和结构清晰度。 ... [详细]
  • 深入解析RDMA中的队列对(Queue Pair)
    本文将详细探讨RDMA架构中的关键组件——队列对(Queue Pair,简称QP),包括其基本概念、硬件与软件实现、QPC的作用、QPN的分配机制以及用户接口和状态机。通过这些内容,读者可以更全面地理解QP在RDMA通信中的重要性和工作原理。 ... [详细]
  • 本文档汇总了Python编程的基础与高级面试题目,涵盖语言特性、数据结构、算法以及Web开发等多个方面,旨在帮助开发者全面掌握Python核心知识。 ... [详细]
  • 深入浅出TensorFlow数据读写机制
    本文详细介绍TensorFlow中的数据读写操作,包括TFRecord文件的创建与读取,以及数据集(dataset)的相关概念和使用方法。 ... [详细]
  • 本文探讨了一个特定于 Spring 4.2.5 的问题,即在应用上下文刷新事件(ContextRefreshedEvent)触发时,带有 @Transactional 注解的 Bean 未能正确代理事务。该问题在 Spring 4.1.9 版本中正常运行,但在升级至 4.2.5 后出现异常。 ... [详细]
author-avatar
万世一统_425
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有